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

This commit is contained in:
John W. Linville 2013-01-28 14:43:00 -05:00
commit 4205e6ef4e
210 changed files with 7767 additions and 5052 deletions

View file

@ -17,10 +17,12 @@ HCI
HCI registers as an nfc device with NFC Core. Requests coming from userspace are
routed through netlink sockets to NFC Core and then to HCI. From this point,
they are translated in a sequence of HCI commands sent to the HCI layer in the
host controller (the chip). The sending context blocks while waiting for the
response to arrive.
host controller (the chip). Commands can be executed synchronously (the sending
context blocks waiting for response) or asynchronously (the response is returned
from HCI Rx context).
HCI events can also be received from the host controller. They will be handled
and a translation will be forwarded to NFC Core as needed.
and a translation will be forwarded to NFC Core as needed. There are hooks to
let the HCI driver handle proprietary events or override standard behavior.
HCI uses 2 execution contexts:
- one for executing commands : nfc_hci_msg_tx_work(). Only one command
can be executing at any given moment.
@ -33,6 +35,8 @@ The Session initialization is an HCI standard which must unfortunately
support proprietary gates. This is the reason why the driver will pass a list
of proprietary gates that must be part of the session. HCI will ensure all
those gates have pipes connected when the hci device is set up.
In case the chip supports pre-opened gates and pseudo-static pipes, the driver
can pass that information to HCI core.
HCI Gates and Pipes
-------------------
@ -46,6 +50,13 @@ without knowing the pipe connected to it.
Driver interface
----------------
A driver is generally written in two parts : the physical link management and
the HCI management. This makes it easier to maintain a driver for a chip that
can be connected using various phy (i2c, spi, ...)
HCI Management
--------------
A driver would normally register itself with HCI and provide the following
entry points:
@ -53,58 +64,113 @@ struct nfc_hci_ops {
int (*open)(struct nfc_hci_dev *hdev);
void (*close)(struct nfc_hci_dev *hdev);
int (*hci_ready) (struct nfc_hci_dev *hdev);
int (*xmit)(struct nfc_hci_dev *hdev, struct sk_buff *skb);
int (*start_poll)(struct nfc_hci_dev *hdev, u32 protocols);
int (*target_from_gate)(struct nfc_hci_dev *hdev, u8 gate,
struct nfc_target *target);
int (*xmit) (struct nfc_hci_dev *hdev, struct sk_buff *skb);
int (*start_poll) (struct nfc_hci_dev *hdev,
u32 im_protocols, u32 tm_protocols);
int (*dep_link_up)(struct nfc_hci_dev *hdev, struct nfc_target *target,
u8 comm_mode, u8 *gb, size_t gb_len);
int (*dep_link_down)(struct nfc_hci_dev *hdev);
int (*target_from_gate) (struct nfc_hci_dev *hdev, u8 gate,
struct nfc_target *target);
int (*complete_target_discovered) (struct nfc_hci_dev *hdev, u8 gate,
struct nfc_target *target);
int (*data_exchange) (struct nfc_hci_dev *hdev,
struct nfc_target *target,
struct sk_buff *skb, struct sk_buff **res_skb);
int (*im_transceive) (struct nfc_hci_dev *hdev,
struct nfc_target *target, struct sk_buff *skb,
data_exchange_cb_t cb, void *cb_context);
int (*tm_send)(struct nfc_hci_dev *hdev, struct sk_buff *skb);
int (*check_presence)(struct nfc_hci_dev *hdev,
struct nfc_target *target);
int (*event_received)(struct nfc_hci_dev *hdev, u8 gate, u8 event,
struct sk_buff *skb);
};
- open() and close() shall turn the hardware on and off.
- hci_ready() is an optional entry point that is called right after the hci
session has been set up. The driver can use it to do additional initialization
that must be performed using HCI commands.
- xmit() shall simply write a frame to the chip.
- xmit() shall simply write a frame to the physical link.
- start_poll() is an optional entrypoint that shall set the hardware in polling
mode. This must be implemented only if the hardware uses proprietary gates or a
mechanism slightly different from the HCI standard.
- dep_link_up() is called after a p2p target has been detected, to finish
the p2p connection setup with hardware parameters that need to be passed back
to nfc core.
- dep_link_down() is called to bring the p2p link down.
- target_from_gate() is an optional entrypoint to return the nfc protocols
corresponding to a proprietary gate.
- complete_target_discovered() is an optional entry point to let the driver
perform additional proprietary processing necessary to auto activate the
discovered target.
- data_exchange() must be implemented by the driver if proprietary HCI commands
- im_transceive() must be implemented by the driver if proprietary HCI commands
are required to send data to the tag. Some tag types will require custom
commands, others can be written to using the standard HCI commands. The driver
can check the tag type and either do proprietary processing, or return 1 to ask
for standard processing.
for standard processing. The data exchange command itself must be sent
asynchronously.
- tm_send() is called to send data in the case of a p2p connection
- check_presence() is an optional entry point that will be called regularly
by the core to check that an activated tag is still in the field. If this is
not implemented, the core will not be able to push tag_lost events to the user
space
- event_received() is called to handle an event coming from the chip. Driver
can handle the event or return 1 to let HCI attempt standard processing.
On the rx path, the driver is responsible to push incoming HCP frames to HCI
using nfc_hci_recv_frame(). HCI will take care of re-aggregation and handling
This must be done from a context that can sleep.
SHDLC
-----
PHY Management
--------------
Most chips use shdlc to ensure integrity and delivery ordering of the HCP
frames between the host controller (the chip) and hosts (entities connected
to the chip, like the cpu). In order to simplify writing the driver, an shdlc
layer is available for use by the driver.
When used, the driver actually registers with shdlc, and shdlc will register
with HCI. HCI sees shdlc as the driver and thus send its HCP frames
through shdlc->xmit.
SHDLC adds a new execution context (nfc_shdlc_sm_work()) to run its state
machine and handle both its rx and tx path.
The physical link (i2c, ...) management is defined by the following struture:
struct nfc_phy_ops {
int (*write)(void *dev_id, struct sk_buff *skb);
int (*enable)(void *dev_id);
void (*disable)(void *dev_id);
};
enable(): turn the phy on (power on), make it ready to transfer data
disable(): turn the phy off
write(): Send a data frame to the chip. Note that to enable higher
layers such as an llc to store the frame for re-emission, this function must
not alter the skb. It must also not return a positive result (return 0 for
success, negative for failure).
Data coming from the chip shall be sent directly to nfc_hci_recv_frame().
LLC
---
Communication between the CPU and the chip often requires some link layer
protocol. Those are isolated as modules managed by the HCI layer. There are
currently two modules : nop (raw transfert) and shdlc.
A new llc must implement the following functions:
struct nfc_llc_ops {
void *(*init) (struct nfc_hci_dev *hdev, xmit_to_drv_t xmit_to_drv,
rcv_to_hci_t rcv_to_hci, int tx_headroom,
int tx_tailroom, int *rx_headroom, int *rx_tailroom,
llc_failure_t llc_failure);
void (*deinit) (struct nfc_llc *llc);
int (*start) (struct nfc_llc *llc);
int (*stop) (struct nfc_llc *llc);
void (*rcv_from_drv) (struct nfc_llc *llc, struct sk_buff *skb);
int (*xmit_from_hci) (struct nfc_llc *llc, struct sk_buff *skb);
};
- init() : allocate and init your private storage
- deinit() : cleanup
- start() : establish the logical connection
- stop () : terminate the logical connection
- rcv_from_drv() : handle data coming from the chip, going to HCI
- xmit_from_hci() : handle data sent by HCI, going to the chip
The llc must be registered with nfc before it can be used. Do that by
calling nfc_llc_register(const char *name, struct nfc_llc_ops *ops);
Again, note that the llc does not handle the physical link. It is thus very
easy to mix any physical link with any llc for a given chip driver.
Included Drivers
----------------
@ -117,10 +183,12 @@ Execution Contexts
The execution contexts are the following:
- IRQ handler (IRQH):
fast, cannot sleep. stores incoming frames into an shdlc rx queue
fast, cannot sleep. sends incoming frames to HCI where they are passed to
the current llc. In case of shdlc, the frame is queued in shdlc rx queue.
- SHDLC State Machine worker (SMW)
handles shdlc rx & tx queues. Dispatches HCI cmd responses.
Only when llc_shdlc is used: handles shdlc rx & tx queues.
Dispatches HCI cmd responses.
- HCI Tx Cmd worker (MSGTXWQ)
Serializes execution of HCI commands. Completes execution in case of response
@ -166,6 +234,15 @@ waiting command execution. Response processing involves invoking the completion
callback that was provided by nfc_hci_msg_tx_work() when it sent the command.
The completion callback will then wake the syscall context.
It is also possible to execute the command asynchronously using this API:
static int nfc_hci_execute_cmd_async(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd,
const u8 *param, size_t param_len,
data_exchange_cb_t cb, void *cb_context)
The workflow is the same, except that the API call returns immediately, and
the callback will be called with the result from the SMW context.
Workflow receiving an HCI event or command
------------------------------------------

View file

@ -1,32 +1,15 @@
Kernel driver for the NXP Semiconductors PN544 Near Field
Communication chip
Author: Jari Vanhala
Contact: Matti Aaltonen (matti.j.aaltonen at nokia.com)
General
-------
The PN544 is an integrated transmission module for contactless
communication. The driver goes under drives/nfc/ and is compiled as a
module named "pn544". It registers a misc device and creates a device
file named "/dev/pn544".
module named "pn544".
Host Interfaces: I2C, SPI and HSU, this driver supports currently only I2C.
The Interface
-------------
The driver offers a sysfs interface for a hardware test and an IOCTL
interface for selecting between two operating modes. There are read,
write and poll functions for transferring messages. The two operating
modes are the normal (HCI) mode and the firmware update mode.
PN544 is controlled by sending messages from the userspace to the
chip. The main function of the driver is just to pass those messages
without caring about the message content.
Protocols
---------
@ -47,68 +30,3 @@ and third (LSB) bytes of the message. The maximum FW message length is
For the ETSI HCI specification see
http://www.etsi.org/WebSite/Technologies/ProtocolSpecification.aspx
The Hardware Test
-----------------
The idea of the test is that it can performed by reading from the
corresponding sysfs file. The test is implemented in the board file
and it should test that PN544 can be put into the firmware update
mode. If the test is not implemented the sysfs file does not get
created.
Example:
> cat /sys/module/pn544/drivers/i2c\:pn544/3-002b/nfc_test
1
Normal Operation
----------------
PN544 is powered up when the device file is opened, otherwise it's
turned off. Only one instance can use the device at a time.
Userspace applications control PN544 with HCI messages. The hardware
sends an interrupt when data is available for reading. Data is
physically read when the read function is called by a userspace
application. Poll() checks the read interrupt state. Configuration and
self testing are also done from the userspace using read and write.
Example platform data:
static int rx71_pn544_nfc_request_resources(struct i2c_client *client)
{
/* Get and setup the HW resources for the device */
}
static void rx71_pn544_nfc_free_resources(void)
{
/* Release the HW resources */
}
static void rx71_pn544_nfc_enable(int fw)
{
/* Turn the device on */
}
static int rx71_pn544_nfc_test(void)
{
/*
* Put the device into the FW update mode
* and then back to the normal mode.
* Check the behavior and return one on success,
* zero on failure.
*/
}
static void rx71_pn544_nfc_disable(void)
{
/* turn the power off */
}
static struct pn544_nfc_platform_data rx71_nfc_data = {
.request_resources = rx71_pn544_nfc_request_resources,
.free_resources = rx71_pn544_nfc_free_resources,
.enable = rx71_pn544_nfc_enable,
.test = rx71_pn544_nfc_test,
.disable = rx71_pn544_nfc_disable,
};

View file

@ -62,7 +62,7 @@ static int __init uart8250_init_bcma(void)
p->mapbase = (unsigned int) bcma_port->regs;
p->membase = (void *) bcma_port->regs;
p->irq = bcma_port->irq + 2;
p->irq = bcma_port->irq;
p->uartclk = bcma_port->baud_base;
p->regshift = bcma_port->reg_shift;
p->iotype = UPIO_MEM;

View file

@ -31,6 +31,8 @@ int __init bcma_bus_early_register(struct bcma_bus *bus,
int bcma_bus_suspend(struct bcma_bus *bus);
int bcma_bus_resume(struct bcma_bus *bus);
#endif
struct bcma_device *bcma_find_core_unit(struct bcma_bus *bus, u16 coreid,
u8 unit);
/* scan.c */
int bcma_bus_scan(struct bcma_bus *bus);

View file

@ -329,7 +329,7 @@ void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
return;
}
irq = bcma_core_mips_irq(cc->core);
irq = bcma_core_irq(cc->core);
/* Determine the registers of the UARTs */
cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART);

View file

@ -74,28 +74,41 @@ static u32 bcma_core_mips_irqflag(struct bcma_device *dev)
return dev->core_index;
flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30);
return flag & 0x1F;
if (flag)
return flag & 0x1F;
else
return 0x3f;
}
/* Get the MIPS IRQ assignment for a specified device.
* If unassigned, 0 is returned.
* If disabled, 5 is returned.
* If not supported, 6 is returned.
*/
unsigned int bcma_core_mips_irq(struct bcma_device *dev)
static unsigned int bcma_core_mips_irq(struct bcma_device *dev)
{
struct bcma_device *mdev = dev->bus->drv_mips.core;
u32 irqflag;
unsigned int irq;
irqflag = bcma_core_mips_irqflag(dev);
if (irqflag == 0x3f)
return 6;
for (irq = 1; irq <= 4; irq++)
for (irq = 0; irq <= 4; irq++)
if (bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq)) &
(1 << irqflag))
return irq;
return 0;
return 5;
}
EXPORT_SYMBOL(bcma_core_mips_irq);
unsigned int bcma_core_irq(struct bcma_device *dev)
{
unsigned int mips_irq = bcma_core_mips_irq(dev);
return mips_irq <= 4 ? mips_irq + 2 : 0;
}
EXPORT_SYMBOL(bcma_core_irq);
static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
{
@ -114,7 +127,7 @@ static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) &
~(1 << irqflag));
else
else if (oldirq != 5)
bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(oldirq), 0);
/* assign the new one */
@ -123,9 +136,9 @@ static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) |
(1 << irqflag));
} else {
u32 oldirqflag = bcma_read32(mdev,
BCMA_MIPS_MIPS74K_INTMASK(irq));
if (oldirqflag) {
u32 irqinitmask = bcma_read32(mdev,
BCMA_MIPS_MIPS74K_INTMASK(irq));
if (irqinitmask) {
struct bcma_device *core;
/* backplane irq line is in use, find out who uses
@ -133,7 +146,7 @@ static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
*/
list_for_each_entry(core, &bus->cores, list) {
if ((1 << bcma_core_mips_irqflag(core)) ==
oldirqflag) {
irqinitmask) {
bcma_core_mips_set_irq(core, 0);
break;
}
@ -143,15 +156,31 @@ static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
1 << irqflag);
}
bcma_info(bus, "set_irq: core 0x%04x, irq %d => %d\n",
dev->id.id, oldirq + 2, irq + 2);
bcma_debug(bus, "set_irq: core 0x%04x, irq %d => %d\n",
dev->id.id, oldirq <= 4 ? oldirq + 2 : 0, irq + 2);
}
static void bcma_core_mips_set_irq_name(struct bcma_bus *bus, unsigned int irq,
u16 coreid, u8 unit)
{
struct bcma_device *core;
core = bcma_find_core_unit(bus, coreid, unit);
if (!core) {
bcma_warn(bus,
"Can not find core (id: 0x%x, unit %i) for IRQ configuration.\n",
coreid, unit);
return;
}
bcma_core_mips_set_irq(core, irq);
}
static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq)
{
int i;
static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
printk(KERN_INFO KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id);
printk(KERN_DEBUG KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id);
for (i = 0; i <= 6; i++)
printk(" %s%s", irq_name[i], i == irq ? "*" : " ");
printk("\n");
@ -227,6 +256,32 @@ void bcma_core_mips_early_init(struct bcma_drv_mips *mcore)
mcore->early_setup_done = true;
}
static void bcma_fix_i2s_irqflag(struct bcma_bus *bus)
{
struct bcma_device *cpu, *pcie, *i2s;
/* Fixup the interrupts in 4716/4748 for i2s core (2010 Broadcom SDK)
* (IRQ flags > 7 are ignored when setting the interrupt masks)
*/
if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4716 &&
bus->chipinfo.id != BCMA_CHIP_ID_BCM4748)
return;
cpu = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
pcie = bcma_find_core(bus, BCMA_CORE_PCIE);
i2s = bcma_find_core(bus, BCMA_CORE_I2S);
if (cpu && pcie && i2s &&
bcma_aread32(cpu, BCMA_MIPS_OOBSELINA74) == 0x08060504 &&
bcma_aread32(pcie, BCMA_MIPS_OOBSELINA74) == 0x08060504 &&
bcma_aread32(i2s, BCMA_MIPS_OOBSELOUTA30) == 0x88) {
bcma_awrite32(cpu, BCMA_MIPS_OOBSELINA74, 0x07060504);
bcma_awrite32(pcie, BCMA_MIPS_OOBSELINA74, 0x07060504);
bcma_awrite32(i2s, BCMA_MIPS_OOBSELOUTA30, 0x87);
bcma_debug(bus,
"Moved i2s interrupt to oob line 7 instead of 8\n");
}
}
void bcma_core_mips_init(struct bcma_drv_mips *mcore)
{
struct bcma_bus *bus;
@ -236,43 +291,55 @@ void bcma_core_mips_init(struct bcma_drv_mips *mcore)
if (mcore->setup_done)
return;
bcma_info(bus, "Initializing MIPS core...\n");
bcma_debug(bus, "Initializing MIPS core...\n");
bcma_core_mips_early_init(mcore);
mcore->assigned_irqs = 1;
bcma_fix_i2s_irqflag(bus);
/* Assign IRQs to all cores on the bus */
list_for_each_entry(core, &bus->cores, list) {
int mips_irq;
if (core->irq)
continue;
mips_irq = bcma_core_mips_irq(core);
if (mips_irq > 4)
core->irq = 0;
else
core->irq = mips_irq + 2;
if (core->irq > 5)
continue;
switch (core->id.id) {
case BCMA_CORE_PCI:
case BCMA_CORE_PCIE:
case BCMA_CORE_ETHERNET:
case BCMA_CORE_ETHERNET_GBIT:
case BCMA_CORE_MAC_GBIT:
case BCMA_CORE_80211:
case BCMA_CORE_USB20_HOST:
/* These devices get their own IRQ line if available,
* the rest goes on IRQ0
*/
if (mcore->assigned_irqs <= 4)
bcma_core_mips_set_irq(core,
mcore->assigned_irqs++);
break;
switch (bus->chipinfo.id) {
case BCMA_CHIP_ID_BCM4716:
case BCMA_CHIP_ID_BCM4748:
bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_80211, 0);
bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_MAC_GBIT, 0);
bcma_core_mips_set_irq_name(bus, 3, BCMA_CORE_USB20_HOST, 0);
bcma_core_mips_set_irq_name(bus, 4, BCMA_CORE_PCIE, 0);
bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_CHIPCOMMON, 0);
bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_I2S, 0);
break;
case BCMA_CHIP_ID_BCM5356:
case BCMA_CHIP_ID_BCM47162:
case BCMA_CHIP_ID_BCM53572:
bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_80211, 0);
bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_MAC_GBIT, 0);
bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_CHIPCOMMON, 0);
break;
case BCMA_CHIP_ID_BCM5357:
case BCMA_CHIP_ID_BCM4749:
bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_80211, 0);
bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_MAC_GBIT, 0);
bcma_core_mips_set_irq_name(bus, 3, BCMA_CORE_USB20_HOST, 0);
bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_CHIPCOMMON, 0);
bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_I2S, 0);
break;
case BCMA_CHIP_ID_BCM4706:
bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_PCIE, 0);
bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_4706_MAC_GBIT,
0);
bcma_core_mips_set_irq_name(bus, 3, BCMA_CORE_PCIE, 1);
bcma_core_mips_set_irq_name(bus, 4, BCMA_CORE_USB20_HOST, 0);
bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_4706_CHIPCOMMON,
0);
break;
default:
list_for_each_entry(core, &bus->cores, list) {
core->irq = bcma_core_irq(core);
}
bcma_err(bus,
"Unknown device (0x%x) found, can not configure IRQs\n",
bus->chipinfo.id);
}
bcma_info(bus, "IRQ reconfiguration done\n");
bcma_debug(bus, "IRQ reconfiguration done\n");
bcma_core_mips_dump_irq(bus);
mcore->setup_done = true;

View file

@ -94,19 +94,19 @@ static int bcma_extpci_read_config(struct bcma_drv_pci *pc, unsigned int dev,
if (dev == 0) {
/* we support only two functions on device 0 */
if (func > 1)
return -EINVAL;
goto out;
/* accesses to config registers with offsets >= 256
* requires indirect access.
*/
if (off >= PCI_CONFIG_SPACE_SIZE) {
addr = (func << 12);
addr |= (off & 0x0FFF);
addr |= (off & 0x0FFC);
val = bcma_pcie_read_config(pc, addr);
} else {
addr = BCMA_CORE_PCI_PCICFG0;
addr |= (func << 8);
addr |= (off & 0xfc);
addr |= (off & 0xFC);
val = pcicore_read32(pc, addr);
}
} else {
@ -119,11 +119,9 @@ static int bcma_extpci_read_config(struct bcma_drv_pci *pc, unsigned int dev,
goto out;
if (mips_busprobe32(val, mmio)) {
val = 0xffffffff;
val = 0xFFFFFFFF;
goto unmap;
}
val = readl(mmio);
}
val >>= (8 * (off & 3));
@ -151,7 +149,7 @@ static int bcma_extpci_write_config(struct bcma_drv_pci *pc, unsigned int dev,
const void *buf, int len)
{
int err = -EINVAL;
u32 addr = 0, val = 0;
u32 addr, val;
void __iomem *mmio = 0;
u16 chipid = pc->core->bus->chipinfo.id;
@ -159,16 +157,22 @@ static int bcma_extpci_write_config(struct bcma_drv_pci *pc, unsigned int dev,
if (unlikely(len != 1 && len != 2 && len != 4))
goto out;
if (dev == 0) {
/* we support only two functions on device 0 */
if (func > 1)
goto out;
/* accesses to config registers with offsets >= 256
* requires indirect access.
*/
if (off < PCI_CONFIG_SPACE_SIZE) {
addr = pc->core->addr + BCMA_CORE_PCI_PCICFG0;
if (off >= PCI_CONFIG_SPACE_SIZE) {
addr = (func << 12);
addr |= (off & 0x0FFC);
val = bcma_pcie_read_config(pc, addr);
} else {
addr = BCMA_CORE_PCI_PCICFG0;
addr |= (func << 8);
addr |= (off & 0xfc);
mmio = ioremap_nocache(addr, sizeof(val));
if (!mmio)
goto out;
addr |= (off & 0xFC);
val = pcicore_read32(pc, addr);
}
} else {
addr = bcma_get_cfgspace_addr(pc, dev, func, off);
@ -180,19 +184,17 @@ static int bcma_extpci_write_config(struct bcma_drv_pci *pc, unsigned int dev,
goto out;
if (mips_busprobe32(val, mmio)) {
val = 0xffffffff;
val = 0xFFFFFFFF;
goto unmap;
}
}
switch (len) {
case 1:
val = readl(mmio);
val &= ~(0xFF << (8 * (off & 3)));
val |= *((const u8 *)buf) << (8 * (off & 3));
break;
case 2:
val = readl(mmio);
val &= ~(0xFFFF << (8 * (off & 3)));
val |= *((const u16 *)buf) << (8 * (off & 3));
break;
@ -200,13 +202,14 @@ static int bcma_extpci_write_config(struct bcma_drv_pci *pc, unsigned int dev,
val = *((const u32 *)buf);
break;
}
if (dev == 0 && !addr) {
if (dev == 0) {
/* accesses to config registers with offsets >= 256
* requires indirect access.
*/
addr = (func << 12);
addr |= (off & 0x0FFF);
bcma_pcie_write_config(pc, addr, val);
if (off >= PCI_CONFIG_SPACE_SIZE)
bcma_pcie_write_config(pc, addr, val);
else
pcicore_write32(pc, addr, val);
} else {
writel(val, mmio);
@ -276,7 +279,7 @@ static u8 bcma_find_pci_capability(struct bcma_drv_pci *pc, unsigned int dev,
/* check for Header type 0 */
bcma_extpci_read_config(pc, dev, func, PCI_HEADER_TYPE, &byte_val,
sizeof(u8));
if ((byte_val & 0x7f) != PCI_HEADER_TYPE_NORMAL)
if ((byte_val & 0x7F) != PCI_HEADER_TYPE_NORMAL)
return cap_ptr;
/* check if the capability pointer field exists */
@ -426,7 +429,7 @@ void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
/* Reset RC */
usleep_range(3000, 5000);
pcicore_write32(pc, BCMA_CORE_PCI_CTL, BCMA_CORE_PCI_CTL_RST_OE);
usleep_range(1000, 2000);
msleep(50);
pcicore_write32(pc, BCMA_CORE_PCI_CTL, BCMA_CORE_PCI_CTL_RST |
BCMA_CORE_PCI_CTL_RST_OE);
@ -488,6 +491,17 @@ void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
bcma_core_pci_enable_crs(pc);
if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706 ||
bus->chipinfo.id == BCMA_CHIP_ID_BCM4716) {
u16 val16;
bcma_extpci_read_config(pc, 0, 0, BCMA_CORE_PCI_CFG_DEVCTRL,
&val16, sizeof(val16));
val16 |= (2 << 5); /* Max payload size of 512 */
val16 |= (2 << 12); /* MRRS 512 */
bcma_extpci_write_config(pc, 0, 0, BCMA_CORE_PCI_CFG_DEVCTRL,
&val16, sizeof(val16));
}
/* Enable PCI bridge BAR0 memory & master access */
tmp = PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
bcma_extpci_write_config(pc, 0, 0, PCI_COMMAND, &tmp, sizeof(tmp));
@ -576,7 +590,7 @@ int bcma_core_pci_plat_dev_init(struct pci_dev *dev)
pr_info("PCI: Fixing up device %s\n", pci_name(dev));
/* Fix up interrupt lines */
dev->irq = bcma_core_mips_irq(pc_host->pdev->core) + 2;
dev->irq = bcma_core_irq(pc_host->pdev->core);
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
return 0;
@ -595,6 +609,6 @@ int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev)
pc_host = container_of(dev->bus->ops, struct bcma_drv_pci_host,
pci_ops);
return bcma_core_mips_irq(pc_host->pdev->core) + 2;
return bcma_core_irq(pc_host->pdev->core);
}
EXPORT_SYMBOL(bcma_core_pci_pcibios_map_irq);

View file

@ -81,8 +81,8 @@ struct bcma_device *bcma_find_core(struct bcma_bus *bus, u16 coreid)
}
EXPORT_SYMBOL_GPL(bcma_find_core);
static struct bcma_device *bcma_find_core_unit(struct bcma_bus *bus, u16 coreid,
u8 unit)
struct bcma_device *bcma_find_core_unit(struct bcma_bus *bus, u16 coreid,
u8 unit)
{
struct bcma_device *core;

View file

@ -77,10 +77,15 @@ static struct usb_device_id ath3k_table[] = {
{ USB_DEVICE(0x0CF3, 0x311D) },
{ USB_DEVICE(0x13d3, 0x3375) },
{ USB_DEVICE(0x04CA, 0x3005) },
{ USB_DEVICE(0x04CA, 0x3006) },
{ USB_DEVICE(0x04CA, 0x3008) },
{ USB_DEVICE(0x13d3, 0x3362) },
{ USB_DEVICE(0x0CF3, 0xE004) },
{ USB_DEVICE(0x0930, 0x0219) },
{ USB_DEVICE(0x0489, 0xe057) },
{ USB_DEVICE(0x13d3, 0x3393) },
{ USB_DEVICE(0x0489, 0xe04e) },
{ USB_DEVICE(0x0489, 0xe056) },
/* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xE02C) },
@ -104,10 +109,15 @@ static struct usb_device_id ath3k_blist_tbl[] = {
{ USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
/* Atheros AR5BBU22 with sflash firmware */
{ USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 },

View file

@ -135,10 +135,15 @@ static struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
/* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },

View file

@ -240,13 +240,14 @@ static const struct ath_ops ath5k_common_ops = {
* Driver Initialization *
\***********************/
static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
static void ath5k_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
{
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct ath5k_hw *ah = hw->priv;
struct ath_regulatory *regulatory = ath5k_hw_regulatory(ah);
return ath_reg_notifier_apply(wiphy, request, regulatory);
ath_reg_notifier_apply(wiphy, request, regulatory);
}
/********************\

View file

@ -3492,8 +3492,8 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar)
ath6kl_cfg80211_stop(vif);
}
static int ath6kl_cfg80211_reg_notify(struct wiphy *wiphy,
struct regulatory_request *request)
static void ath6kl_cfg80211_reg_notify(struct wiphy *wiphy,
struct regulatory_request *request)
{
struct ath6kl *ar = wiphy_priv(wiphy);
u32 rates[IEEE80211_NUM_BANDS];
@ -3506,17 +3506,13 @@ static int ath6kl_cfg80211_reg_notify(struct wiphy *wiphy,
request->processed ? " processed" : "",
request->initiator, request->user_reg_hint_type);
/*
* As firmware is not able intersect regdoms, we can only listen to
* cellular hints.
*/
if (request->user_reg_hint_type != NL80211_USER_REG_HINT_CELL_BASE)
return -EOPNOTSUPP;
return;
ret = ath6kl_wmi_set_regdomain_cmd(ar->wmi, request->alpha2);
if (ret) {
ath6kl_err("failed to set regdomain: %d\n", ret);
return ret;
return;
}
/*
@ -3536,10 +3532,8 @@ static int ath6kl_cfg80211_reg_notify(struct wiphy *wiphy,
if (ret) {
ath6kl_err("failed to start scan for a regdomain change: %d\n",
ret);
return ret;
return;
}
return 0;
}
static int ath6kl_cfg80211_vif_init(struct ath6kl_vif *vif)

View file

@ -86,29 +86,25 @@ static int ath_ahb_probe(struct platform_device *pdev)
if (!pdev->dev.platform_data) {
dev_err(&pdev->dev, "no platform data specified\n");
ret = -EINVAL;
goto err_out;
return -EINVAL;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
dev_err(&pdev->dev, "no memory resource found\n");
ret = -ENXIO;
goto err_out;
return -ENXIO;
}
mem = ioremap_nocache(res->start, resource_size(res));
mem = devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res));
if (mem == NULL) {
dev_err(&pdev->dev, "ioremap failed\n");
ret = -ENOMEM;
goto err_out;
return -ENOMEM;
}
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res == NULL) {
dev_err(&pdev->dev, "no IRQ resource found\n");
ret = -ENXIO;
goto err_iounmap;
return -ENXIO;
}
irq = res->start;
@ -116,8 +112,7 @@ static int ath_ahb_probe(struct platform_device *pdev)
hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops);
if (hw == NULL) {
dev_err(&pdev->dev, "no memory for ieee80211_hw\n");
ret = -ENOMEM;
goto err_iounmap;
return -ENOMEM;
}
SET_IEEE80211_DEV(hw, &pdev->dev);
@ -156,9 +151,6 @@ static int ath_ahb_probe(struct platform_device *pdev)
err_free_hw:
ieee80211_free_hw(hw);
platform_set_drvdata(pdev, NULL);
err_iounmap:
iounmap(mem);
err_out:
return ret;
}
@ -168,12 +160,10 @@ static int ath_ahb_remove(struct platform_device *pdev)
if (hw) {
struct ath_softc *sc = hw->priv;
void __iomem *mem = sc->mem;
ath9k_deinit_device(sc);
free_irq(sc->irq, sc);
ieee80211_free_hw(sc->hw);
iounmap(mem);
platform_set_drvdata(pdev, NULL);
}

View file

@ -152,7 +152,8 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel,
ath_dbg(common, ANI, "**** ofdmlevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
aniState->ofdmNoiseImmunityLevel,
immunityLevel, BEACON_RSSI(ah),
aniState->rssiThrLow, aniState->rssiThrHigh);
ATH9K_ANI_RSSI_THR_LOW,
ATH9K_ANI_RSSI_THR_HIGH);
if (!scan)
aniState->ofdmNoiseImmunityLevel = immunityLevel;
@ -173,7 +174,7 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel,
weak_sig = entry_ofdm->ofdm_weak_signal_on;
if (ah->opmode == NL80211_IFTYPE_STATION &&
BEACON_RSSI(ah) <= aniState->rssiThrHigh)
BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_HIGH)
weak_sig = true;
if (aniState->ofdmWeakSigDetect != weak_sig)
@ -216,11 +217,11 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel,
ath_dbg(common, ANI, "**** ccklevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
aniState->cckNoiseImmunityLevel, immunityLevel,
BEACON_RSSI(ah), aniState->rssiThrLow,
aniState->rssiThrHigh);
BEACON_RSSI(ah), ATH9K_ANI_RSSI_THR_LOW,
ATH9K_ANI_RSSI_THR_HIGH);
if (ah->opmode == NL80211_IFTYPE_STATION &&
BEACON_RSSI(ah) <= aniState->rssiThrLow &&
BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_LOW &&
immunityLevel > ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI)
immunityLevel = ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI;
@ -418,9 +419,6 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan)
return;
aniState = &ah->curchan->ani;
if (WARN_ON(!aniState))
return;
if (!ath9k_hw_ani_read_counters(ah))
return;
@ -489,23 +487,6 @@ void ath9k_hw_disable_mib_counters(struct ath_hw *ah)
}
EXPORT_SYMBOL(ath9k_hw_disable_mib_counters);
void ath9k_hw_ani_setup(struct ath_hw *ah)
{
int i;
static const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
static const int coarseHigh[] = { -14, -14, -14, -14, -12 };
static const int coarseLow[] = { -64, -64, -64, -64, -70 };
static const int firpwr[] = { -78, -78, -78, -78, -80 };
for (i = 0; i < 5; i++) {
ah->totalSizeDesired[i] = totalSizeDesired[i];
ah->coarse_high[i] = coarseHigh[i];
ah->coarse_low[i] = coarseLow[i];
ah->firpwr[i] = firpwr[i];
}
}
void ath9k_hw_ani_init(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
@ -531,8 +512,6 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
ani->ofdmsTurn = true;
ani->rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
ani->rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
ani->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG;
ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL;
ani->ofdmNoiseImmunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL;

View file

@ -104,7 +104,6 @@ struct ath9k_ani_default {
};
struct ar5416AniState {
struct ath9k_channel *c;
u8 noiseImmunityLevel;
u8 ofdmNoiseImmunityLevel;
u8 cckNoiseImmunityLevel;
@ -113,15 +112,9 @@ struct ar5416AniState {
u8 spurImmunityLevel;
u8 firstepLevel;
u8 ofdmWeakSigDetect;
u8 cckWeakSigThreshold;
u32 listenTime;
int32_t rssiThrLow;
int32_t rssiThrHigh;
u32 ofdmPhyErrCount;
u32 cckPhyErrCount;
int16_t pktRssi[2];
int16_t ofdmErrRssi[2];
int16_t cckErrRssi[2];
struct ath9k_ani_default iniDef;
};
@ -147,7 +140,6 @@ struct ar5416Stats {
void ath9k_enable_mib_counters(struct ath_hw *ah);
void ath9k_hw_disable_mib_counters(struct ath_hw *ah);
void ath9k_hw_ani_setup(struct ath_hw *ah);
void ath9k_hw_ani_init(struct ath_hw *ah);
#endif /* ANI_H */

View file

@ -466,7 +466,7 @@ static const u32 ar5416Bank0[][2] = {
};
static const u32 ar5416BB_RfGain[][3] = {
/* Addr 5G_HT20 5G_HT40 */
/* Addr 5G 2G */
{0x00009a00, 0x00000000, 0x00000000},
{0x00009a04, 0x00000040, 0x00000040},
{0x00009a08, 0x00000080, 0x00000080},
@ -546,12 +546,12 @@ static const u32 ar5416Bank2[][2] = {
};
static const u32 ar5416Bank3[][3] = {
/* Addr 5G_HT20 5G_HT40 */
/* Addr 5G 2G */
{0x000098f0, 0x01400018, 0x01c00018},
};
static const u32 ar5416Bank6[][3] = {
/* Addr 5G_HT20 5G_HT40 */
/* Addr 5G 2G */
{0x0000989c, 0x00000000, 0x00000000},
{0x0000989c, 0x00000000, 0x00000000},
{0x0000989c, 0x00000000, 0x00000000},
@ -588,7 +588,7 @@ static const u32 ar5416Bank6[][3] = {
};
static const u32 ar5416Bank6TPC[][3] = {
/* Addr 5G_HT20 5G_HT40 */
/* Addr 5G 2G */
{0x0000989c, 0x00000000, 0x00000000},
{0x0000989c, 0x00000000, 0x00000000},
{0x0000989c, 0x00000000, 0x00000000},

View file

@ -470,16 +470,15 @@ static void ar5008_hw_spur_mitigate(struct ath_hw *ah,
static int ar5008_hw_rf_alloc_ext_banks(struct ath_hw *ah)
{
#define ATH_ALLOC_BANK(bank, size) do { \
bank = kzalloc((sizeof(u32) * size), GFP_KERNEL); \
if (!bank) { \
ath_err(common, "Cannot allocate RF banks\n"); \
return -ENOMEM; \
} \
bank = devm_kzalloc(ah->dev, sizeof(u32) * size, GFP_KERNEL); \
if (!bank) \
goto error; \
} while (0);
struct ath_common *common = ath9k_hw_common(ah);
BUG_ON(AR_SREV_9280_20_OR_LATER(ah));
if (AR_SREV_9280_20_OR_LATER(ah))
return 0;
ATH_ALLOC_BANK(ah->analogBank0Data, ah->iniBank0.ia_rows);
ATH_ALLOC_BANK(ah->analogBank1Data, ah->iniBank1.ia_rows);
@ -492,35 +491,12 @@ static int ar5008_hw_rf_alloc_ext_banks(struct ath_hw *ah)
return 0;
#undef ATH_ALLOC_BANK
error:
ath_err(common, "Cannot allocate RF banks\n");
return -ENOMEM;
}
/**
* ar5008_hw_rf_free_ext_banks - Free memory for analog bank scratch buffers
* @ah: atheros hardware struture
* For the external AR2133/AR5133 radios banks.
*/
static void ar5008_hw_rf_free_ext_banks(struct ath_hw *ah)
{
#define ATH_FREE_BANK(bank) do { \
kfree(bank); \
bank = NULL; \
} while (0);
BUG_ON(AR_SREV_9280_20_OR_LATER(ah));
ATH_FREE_BANK(ah->analogBank0Data);
ATH_FREE_BANK(ah->analogBank1Data);
ATH_FREE_BANK(ah->analogBank2Data);
ATH_FREE_BANK(ah->analogBank3Data);
ATH_FREE_BANK(ah->analogBank6Data);
ATH_FREE_BANK(ah->analogBank6TPCData);
ATH_FREE_BANK(ah->analogBank7Data);
ATH_FREE_BANK(ah->bank6Temp);
#undef ATH_FREE_BANK
}
/* *
* ar5008_hw_set_rf_regs - programs rf registers based on EEPROM
* @ah: atheros hardware structure
@ -1380,7 +1356,7 @@ static void ar5008_hw_set_radar_conf(struct ath_hw *ah)
conf->radar_inband = 8;
}
void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
int ar5008_hw_attach_phy_ops(struct ath_hw *ah)
{
struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
static const u32 ar5416_cca_regs[6] = {
@ -1391,12 +1367,15 @@ void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
AR_PHY_CH1_EXT_CCA,
AR_PHY_CH2_EXT_CCA
};
int ret;
ret = ar5008_hw_rf_alloc_ext_banks(ah);
if (ret)
return ret;
priv_ops->rf_set_freq = ar5008_hw_set_channel;
priv_ops->spur_mitigate_freq = ar5008_hw_spur_mitigate;
priv_ops->rf_alloc_ext_banks = ar5008_hw_rf_alloc_ext_banks;
priv_ops->rf_free_ext_banks = ar5008_hw_rf_free_ext_banks;
priv_ops->set_rf_regs = ar5008_hw_set_rf_regs;
priv_ops->set_channel_regs = ar5008_hw_set_channel_regs;
priv_ops->init_bb = ar5008_hw_init_bb;
@ -1421,4 +1400,5 @@ void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
ar5008_hw_set_nf_limits(ah);
ar5008_hw_set_radar_conf(ah);
memcpy(ah->nf_regs, ar5416_cca_regs, sizeof(ah->nf_regs));
return 0;
}

View file

@ -460,7 +460,7 @@ static const u32 ar5416Common_9100[][2] = {
};
static const u32 ar5416Bank6_9100[][3] = {
/* Addr 5G_HT20 5G_HT40 */
/* Addr 5G 2G */
{0x0000989c, 0x00000000, 0x00000000},
{0x0000989c, 0x00000000, 0x00000000},
{0x0000989c, 0x00000000, 0x00000000},
@ -497,7 +497,7 @@ static const u32 ar5416Bank6_9100[][3] = {
};
static const u32 ar5416Bank6TPC_9100[][3] = {
/* Addr 5G_HT20 5G_HT40 */
/* Addr 5G 2G */
{0x0000989c, 0x00000000, 0x00000000},
{0x0000989c, 0x00000000, 0x00000000},
{0x0000989c, 0x00000000, 0x00000000},

View file

@ -23,13 +23,13 @@
/* General hardware code for the A5008/AR9001/AR9002 hadware families */
static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
static int ar9002_hw_init_mode_regs(struct ath_hw *ah)
{
if (AR_SREV_9271(ah)) {
INIT_INI_ARRAY(&ah->iniModes, ar9271Modes_9271);
INIT_INI_ARRAY(&ah->iniCommon, ar9271Common_9271);
INIT_INI_ARRAY(&ah->iniModes_9271_ANI_reg, ar9271Modes_9271_ANI_reg);
return;
return 0;
}
if (ah->config.pcie_clock_req)
@ -102,9 +102,9 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
u32 size = sizeof(u32) * addac->ia_rows * addac->ia_columns;
u32 *data;
data = kmalloc(size, GFP_KERNEL);
data = devm_kzalloc(ah->dev, size, GFP_KERNEL);
if (!data)
return;
return -ENOMEM;
memcpy(data, addac->ia_array, size);
addac->ia_array = data;
@ -120,6 +120,7 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
ar9287Common_japan_2484_cck_fir_coeff_9287_1_1);
}
return 0;
}
static void ar9280_20_hw_init_rxgain_ini(struct ath_hw *ah)
@ -409,22 +410,30 @@ void ar9002_hw_enable_async_fifo(struct ath_hw *ah)
}
/* Sets up the AR5008/AR9001/AR9002 hardware familiy callbacks */
void ar9002_hw_attach_ops(struct ath_hw *ah)
int ar9002_hw_attach_ops(struct ath_hw *ah)
{
struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
struct ath_hw_ops *ops = ath9k_hw_ops(ah);
int ret;
ret = ar9002_hw_init_mode_regs(ah);
if (ret)
return ret;
priv_ops->init_mode_regs = ar9002_hw_init_mode_regs;
priv_ops->init_mode_gain_regs = ar9002_hw_init_mode_gain_regs;
ops->config_pci_powersave = ar9002_hw_configpcipowersave;
ar5008_hw_attach_phy_ops(ah);
ret = ar5008_hw_attach_phy_ops(ah);
if (ret)
return ret;
if (AR_SREV_9280_20_OR_LATER(ah))
ar9002_hw_attach_phy_ops(ah);
ar9002_hw_attach_calib_ops(ah);
ar9002_hw_attach_mac_ops(ah);
return 0;
}
void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan)

View file

@ -555,14 +555,73 @@ static void ar9002_hw_antdiv_comb_conf_set(struct ath_hw *ah,
REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regval);
}
static void ar9002_hw_spectral_scan_config(struct ath_hw *ah,
struct ath_spec_scan *param)
{
u8 count;
if (!param->enabled) {
REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN,
AR_PHY_SPECTRAL_SCAN_ENABLE);
return;
}
REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_FFT_ENA);
REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENABLE);
if (param->short_repeat)
REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT);
else
REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN,
AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT);
/* on AR92xx, the highest bit of count will make the the chip send
* spectral samples endlessly. Check if this really was intended,
* and fix otherwise.
*/
count = param->count;
if (param->endless)
count = 0x80;
else if (count & 0x80)
count = 0x7f;
REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
AR_PHY_SPECTRAL_SCAN_COUNT, count);
REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
AR_PHY_SPECTRAL_SCAN_PERIOD, param->period);
REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
AR_PHY_SPECTRAL_SCAN_FFT_PERIOD, param->fft_period);
return;
}
static void ar9002_hw_spectral_scan_trigger(struct ath_hw *ah)
{
REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENABLE);
/* Activate spectral scan */
REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
AR_PHY_SPECTRAL_SCAN_ACTIVE);
}
static void ar9002_hw_spectral_scan_wait(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
/* Poll for spectral scan complete */
if (!ath9k_hw_wait(ah, AR_PHY_SPECTRAL_SCAN,
AR_PHY_SPECTRAL_SCAN_ACTIVE,
0, AH_WAIT_TIMEOUT)) {
ath_err(common, "spectral scan wait failed\n");
return;
}
}
void ar9002_hw_attach_phy_ops(struct ath_hw *ah)
{
struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
struct ath_hw_ops *ops = ath9k_hw_ops(ah);
priv_ops->set_rf_regs = NULL;
priv_ops->rf_alloc_ext_banks = NULL;
priv_ops->rf_free_ext_banks = NULL;
priv_ops->rf_set_freq = ar9002_hw_set_channel;
priv_ops->spur_mitigate_freq = ar9002_hw_spur_mitigate;
priv_ops->olc_init = ar9002_olc_init;
@ -571,6 +630,9 @@ void ar9002_hw_attach_phy_ops(struct ath_hw *ah)
ops->antdiv_comb_conf_get = ar9002_hw_antdiv_comb_conf_get;
ops->antdiv_comb_conf_set = ar9002_hw_antdiv_comb_conf_set;
ops->spectral_scan_config = ar9002_hw_spectral_scan_config;
ops->spectral_scan_trigger = ar9002_hw_spectral_scan_trigger;
ops->spectral_scan_wait = ar9002_hw_spectral_scan_wait;
ar9002_hw_set_nf_limits(ah);
}

View file

@ -744,6 +744,186 @@ static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = {
{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
};
static const u32 ar9300Modes_mixed_ob_db_tx_gain_table_2p2[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x0000a2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
{0x0000a2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
{0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
{0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
{0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
{0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202},
{0x0000a514, 0x1c000223, 0x1c000223, 0x11000400, 0x11000400},
{0x0000a518, 0x21002220, 0x21002220, 0x15000402, 0x15000402},
{0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404},
{0x0000a520, 0x2b022220, 0x2b022220, 0x1b000603, 0x1b000603},
{0x0000a524, 0x2f022222, 0x2f022222, 0x1f000a02, 0x1f000a02},
{0x0000a528, 0x34022225, 0x34022225, 0x23000a04, 0x23000a04},
{0x0000a52c, 0x3a02222a, 0x3a02222a, 0x26000a20, 0x26000a20},
{0x0000a530, 0x3e02222c, 0x3e02222c, 0x2a000e20, 0x2a000e20},
{0x0000a534, 0x4202242a, 0x4202242a, 0x2e000e22, 0x2e000e22},
{0x0000a538, 0x4702244a, 0x4702244a, 0x31000e24, 0x31000e24},
{0x0000a53c, 0x4b02244c, 0x4b02244c, 0x34001640, 0x34001640},
{0x0000a540, 0x4e02246c, 0x4e02246c, 0x38001660, 0x38001660},
{0x0000a544, 0x52022470, 0x52022470, 0x3b001861, 0x3b001861},
{0x0000a548, 0x55022490, 0x55022490, 0x3e001a81, 0x3e001a81},
{0x0000a54c, 0x59022492, 0x59022492, 0x42001a83, 0x42001a83},
{0x0000a550, 0x5d022692, 0x5d022692, 0x44001c84, 0x44001c84},
{0x0000a554, 0x61022892, 0x61022892, 0x48001ce3, 0x48001ce3},
{0x0000a558, 0x65024890, 0x65024890, 0x4c001ce5, 0x4c001ce5},
{0x0000a55c, 0x69024892, 0x69024892, 0x50001ce9, 0x50001ce9},
{0x0000a560, 0x6e024c92, 0x6e024c92, 0x54001ceb, 0x54001ceb},
{0x0000a564, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec},
{0x0000a568, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec},
{0x0000a56c, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec},
{0x0000a570, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec},
{0x0000a574, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec},
{0x0000a578, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec},
{0x0000a57c, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec},
{0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
{0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
{0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
{0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
{0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202},
{0x0000a594, 0x1c800223, 0x1c800223, 0x11800400, 0x11800400},
{0x0000a598, 0x21802220, 0x21802220, 0x15800402, 0x15800402},
{0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404},
{0x0000a5a0, 0x2b822220, 0x2b822220, 0x1b800603, 0x1b800603},
{0x0000a5a4, 0x2f822222, 0x2f822222, 0x1f800a02, 0x1f800a02},
{0x0000a5a8, 0x34822225, 0x34822225, 0x23800a04, 0x23800a04},
{0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x26800a20, 0x26800a20},
{0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2a800e20, 0x2a800e20},
{0x0000a5b4, 0x4282242a, 0x4282242a, 0x2e800e22, 0x2e800e22},
{0x0000a5b8, 0x4782244a, 0x4782244a, 0x31800e24, 0x31800e24},
{0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x34801640, 0x34801640},
{0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x38801660, 0x38801660},
{0x0000a5c4, 0x52822470, 0x52822470, 0x3b801861, 0x3b801861},
{0x0000a5c8, 0x55822490, 0x55822490, 0x3e801a81, 0x3e801a81},
{0x0000a5cc, 0x59822492, 0x59822492, 0x42801a83, 0x42801a83},
{0x0000a5d0, 0x5d822692, 0x5d822692, 0x44801c84, 0x44801c84},
{0x0000a5d4, 0x61822892, 0x61822892, 0x48801ce3, 0x48801ce3},
{0x0000a5d8, 0x65824890, 0x65824890, 0x4c801ce5, 0x4c801ce5},
{0x0000a5dc, 0x69824892, 0x69824892, 0x50801ce9, 0x50801ce9},
{0x0000a5e0, 0x6e824c92, 0x6e824c92, 0x54801ceb, 0x54801ceb},
{0x0000a5e4, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec},
{0x0000a5e8, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec},
{0x0000a5ec, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec},
{0x0000a5f0, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec},
{0x0000a5f4, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec},
{0x0000a5f8, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec},
{0x0000a5fc, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec},
{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a614, 0x02004000, 0x02004000, 0x01404000, 0x01404000},
{0x0000a618, 0x02004801, 0x02004801, 0x01404501, 0x01404501},
{0x0000a61c, 0x02808a02, 0x02808a02, 0x02008501, 0x02008501},
{0x0000a620, 0x0380ce03, 0x0380ce03, 0x0280ca03, 0x0280ca03},
{0x0000a624, 0x04411104, 0x04411104, 0x03010c04, 0x03010c04},
{0x0000a628, 0x04411104, 0x04411104, 0x04014c04, 0x04014c04},
{0x0000a62c, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
{0x0000a630, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
{0x0000a634, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
{0x0000a638, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
{0x0000a63c, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
{0x0000b2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
{0x0000b2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
{0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x0000c2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
{0x0000c2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
{0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
{0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x00016044, 0x012492d4, 0x012492d4, 0x056db2e4, 0x056db2e4},
{0x00016048, 0x66480001, 0x66480001, 0x8e480001, 0x8e480001},
{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
{0x00016444, 0x012492d4, 0x012492d4, 0x056db2e4, 0x056db2e4},
{0x00016448, 0x66480001, 0x66480001, 0x8e480001, 0x8e480001},
{0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
{0x00016844, 0x012492d4, 0x012492d4, 0x056db2e4, 0x056db2e4},
{0x00016848, 0x66480001, 0x66480001, 0x8e480001, 0x8e480001},
{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
};
static const u32 ar9300Modes_type5_tx_gain_table_2p2[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x0000a2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
{0x0000a2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
{0x0000a2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
{0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
{0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
{0x0000a510, 0x15000028, 0x15000028, 0x0f000202, 0x0f000202},
{0x0000a514, 0x1b00002b, 0x1b00002b, 0x12000400, 0x12000400},
{0x0000a518, 0x1f020028, 0x1f020028, 0x16000402, 0x16000402},
{0x0000a51c, 0x2502002b, 0x2502002b, 0x19000404, 0x19000404},
{0x0000a520, 0x2a04002a, 0x2a04002a, 0x1c000603, 0x1c000603},
{0x0000a524, 0x2e06002a, 0x2e06002a, 0x21000a02, 0x21000a02},
{0x0000a528, 0x3302202d, 0x3302202d, 0x25000a04, 0x25000a04},
{0x0000a52c, 0x3804202c, 0x3804202c, 0x28000a20, 0x28000a20},
{0x0000a530, 0x3c06202c, 0x3c06202c, 0x2c000e20, 0x2c000e20},
{0x0000a534, 0x4108202d, 0x4108202d, 0x30000e22, 0x30000e22},
{0x0000a538, 0x4506402d, 0x4506402d, 0x34000e24, 0x34000e24},
{0x0000a53c, 0x4906222d, 0x4906222d, 0x38001640, 0x38001640},
{0x0000a540, 0x4d062231, 0x4d062231, 0x3c001660, 0x3c001660},
{0x0000a544, 0x50082231, 0x50082231, 0x3f001861, 0x3f001861},
{0x0000a548, 0x5608422e, 0x5608422e, 0x43001a81, 0x43001a81},
{0x0000a54c, 0x5e08442e, 0x5e08442e, 0x47001a83, 0x47001a83},
{0x0000a550, 0x620a4431, 0x620a4431, 0x4a001c84, 0x4a001c84},
{0x0000a554, 0x640a4432, 0x640a4432, 0x4e001ce3, 0x4e001ce3},
{0x0000a558, 0x680a4434, 0x680a4434, 0x52001ce5, 0x52001ce5},
{0x0000a55c, 0x6c0a6434, 0x6c0a6434, 0x56001ce9, 0x56001ce9},
{0x0000a560, 0x6f0a6633, 0x6f0a6633, 0x5a001ceb, 0x5a001ceb},
{0x0000a564, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
{0x0000a568, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
{0x0000a56c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
{0x0000a570, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
{0x0000a574, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
{0x0000a578, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
{0x0000a57c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a608, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
{0x0000a60c, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
{0x0000a610, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
{0x0000a614, 0x01804601, 0x01804601, 0x01404000, 0x01404000},
{0x0000a618, 0x01804601, 0x01804601, 0x01404501, 0x01404501},
{0x0000a61c, 0x01804601, 0x01804601, 0x02008501, 0x02008501},
{0x0000a620, 0x03408d02, 0x03408d02, 0x0280ca03, 0x0280ca03},
{0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04},
{0x0000a628, 0x03410d04, 0x03410d04, 0x04014c04, 0x04014c04},
{0x0000a62c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
{0x0000a630, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
{0x0000a634, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
{0x0000a638, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
{0x0000a63c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
{0x0000b2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
{0x0000b2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
{0x0000b2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x0000c2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
{0x0000c2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
{0x0000c2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
{0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
{0x00016048, 0x65240001, 0x65240001, 0x66480001, 0x66480001},
{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
{0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
{0x00016448, 0x65240001, 0x65240001, 0x66480001, 0x66480001},
{0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
{0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
{0x00016848, 0x65240001, 0x65240001, 0x66480001, 0x66480001},
{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
};
static const u32 ar9300Common_rx_gain_table_2p2[][2] = {
/* Addr allmodes */
{0x0000a000, 0x00010000},

View file

@ -32,7 +32,6 @@ struct coeff {
enum ar9003_cal_types {
IQ_MISMATCH_CAL = BIT(0),
TEMP_COMP_CAL = BIT(1),
};
static void ar9003_hw_setup_calibration(struct ath_hw *ah,
@ -49,7 +48,7 @@ static void ar9003_hw_setup_calibration(struct ath_hw *ah,
*/
REG_RMW_FIELD(ah, AR_PHY_TIMING4,
AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX,
currCal->calData->calCountMax);
currCal->calData->calCountMax);
REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
ath_dbg(common, CALIBRATE,
@ -58,14 +57,8 @@ static void ar9003_hw_setup_calibration(struct ath_hw *ah,
/* Kick-off cal */
REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL);
break;
case TEMP_COMP_CAL:
REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM,
AR_PHY_65NM_CH0_THERM_LOCAL, 1);
REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM,
AR_PHY_65NM_CH0_THERM_START, 1);
ath_dbg(common, CALIBRATE,
"starting Temperature Compensation Calibration\n");
default:
ath_err(common, "Invalid calibration type\n");
break;
}
}
@ -323,6 +316,14 @@ static const struct ath9k_percal_data iq_cal_single_sample = {
static void ar9003_hw_init_cal_settings(struct ath_hw *ah)
{
ah->iq_caldata.calData = &iq_cal_single_sample;
if (AR_SREV_9300_20_OR_LATER(ah)) {
ah->enabled_cals |= TX_IQ_CAL;
if (AR_SREV_9485_OR_LATER(ah) && !AR_SREV_9340(ah))
ah->enabled_cals |= TX_IQ_ON_AGC_CAL;
}
ah->supp_cals = IQ_MISMATCH_CAL;
}
/*
@ -959,22 +960,70 @@ static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g)
AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0);
}
static void ar9003_hw_do_manual_peak_cal(struct ath_hw *ah,
struct ath9k_channel *chan)
{
int i;
if (!AR_SREV_9462(ah) && !AR_SREV_9565(ah))
return;
for (i = 0; i < AR9300_MAX_CHAINS; i++) {
if (!(ah->rxchainmask & (1 << i)))
continue;
ar9003_hw_manual_peak_cal(ah, i, IS_CHAN_2GHZ(chan));
}
}
static void ar9003_hw_cl_cal_post_proc(struct ath_hw *ah, bool is_reusable)
{
u32 cl_idx[AR9300_MAX_CHAINS] = { AR_PHY_CL_TAB_0,
AR_PHY_CL_TAB_1,
AR_PHY_CL_TAB_2 };
struct ath9k_hw_cal_data *caldata = ah->caldata;
bool txclcal_done = false;
int i, j;
if (!caldata || !(ah->enabled_cals & TX_CL_CAL))
return;
txclcal_done = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) &
AR_PHY_AGC_CONTROL_CLC_SUCCESS);
if (caldata->done_txclcal_once) {
for (i = 0; i < AR9300_MAX_CHAINS; i++) {
if (!(ah->txchainmask & (1 << i)))
continue;
for (j = 0; j < MAX_CL_TAB_ENTRY; j++)
REG_WRITE(ah, CL_TAB_ENTRY(cl_idx[i]),
caldata->tx_clcal[i][j]);
}
} else if (is_reusable && txclcal_done) {
for (i = 0; i < AR9300_MAX_CHAINS; i++) {
if (!(ah->txchainmask & (1 << i)))
continue;
for (j = 0; j < MAX_CL_TAB_ENTRY; j++)
caldata->tx_clcal[i][j] =
REG_READ(ah, CL_TAB_ENTRY(cl_idx[i]));
}
caldata->done_txclcal_once = true;
}
}
static bool ar9003_hw_init_cal(struct ath_hw *ah,
struct ath9k_channel *chan)
{
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_hw_cal_data *caldata = ah->caldata;
bool txiqcal_done = false, txclcal_done = false;
bool txiqcal_done = false;
bool is_reusable = true, status = true;
bool run_rtt_cal = false, run_agc_cal;
bool run_rtt_cal = false, run_agc_cal, sep_iq_cal = false;
bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT);
u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL |
AR_PHY_AGC_CONTROL_FLTR_CAL |
AR_PHY_AGC_CONTROL_PKDET_CAL;
int i, j;
u32 cl_idx[AR9300_MAX_CHAINS] = { AR_PHY_CL_TAB_0,
AR_PHY_CL_TAB_1,
AR_PHY_CL_TAB_2 };
ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask);
if (rtt) {
if (!ar9003_hw_rtt_restore(ah, chan))
@ -1012,7 +1061,8 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
}
}
if (!(ah->enabled_cals & TX_IQ_CAL))
if ((IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan)) ||
!(ah->enabled_cals & TX_IQ_CAL))
goto skip_tx_iqcal;
/* Do Tx IQ Calibration */
@ -1032,21 +1082,22 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0,
AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);
txiqcal_done = run_agc_cal = true;
goto skip_tx_iqcal;
} else if (caldata && !caldata->done_txiqcal_once)
} else if (caldata && !caldata->done_txiqcal_once) {
run_agc_cal = true;
sep_iq_cal = true;
}
skip_tx_iqcal:
if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal)
ar9003_mci_init_cal_req(ah, &is_reusable);
if (!(IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan))) {
if (sep_iq_cal) {
txiqcal_done = ar9003_hw_tx_iq_cal_run(ah);
REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
udelay(5);
REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
}
skip_tx_iqcal:
if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) {
/* Calibrate the AGC */
REG_WRITE(ah, AR_PHY_AGC_CONTROL,
@ -1057,14 +1108,8 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
AR_PHY_AGC_CONTROL_CAL,
0, AH_WAIT_TIMEOUT);
if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
for (i = 0; i < AR9300_MAX_CHAINS; i++) {
if (!(ah->rxchainmask & (1 << i)))
continue;
ar9003_hw_manual_peak_cal(ah, i,
IS_CHAN_2GHZ(chan));
}
}
ar9003_hw_do_manual_peak_cal(ah, chan);
}
if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal)
@ -1089,31 +1134,7 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
else if (caldata && caldata->done_txiqcal_once)
ar9003_hw_tx_iq_cal_reload(ah);
#define CL_TAB_ENTRY(reg_base) (reg_base + (4 * j))
if (caldata && (ah->enabled_cals & TX_CL_CAL)) {
txclcal_done = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) &
AR_PHY_AGC_CONTROL_CLC_SUCCESS);
if (caldata->done_txclcal_once) {
for (i = 0; i < AR9300_MAX_CHAINS; i++) {
if (!(ah->txchainmask & (1 << i)))
continue;
for (j = 0; j < MAX_CL_TAB_ENTRY; j++)
REG_WRITE(ah, CL_TAB_ENTRY(cl_idx[i]),
caldata->tx_clcal[i][j]);
}
} else if (is_reusable && txclcal_done) {
for (i = 0; i < AR9300_MAX_CHAINS; i++) {
if (!(ah->txchainmask & (1 << i)))
continue;
for (j = 0; j < MAX_CL_TAB_ENTRY; j++)
caldata->tx_clcal[i][j] =
REG_READ(ah,
CL_TAB_ENTRY(cl_idx[i]));
}
caldata->done_txclcal_once = true;
}
}
#undef CL_TAB_ENTRY
ar9003_hw_cl_cal_post_proc(ah, is_reusable);
if (run_rtt_cal && caldata) {
if (is_reusable) {
@ -1131,20 +1152,10 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
/* Initialize list pointers */
ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
ah->supp_cals = IQ_MISMATCH_CAL;
if (ah->supp_cals & IQ_MISMATCH_CAL) {
INIT_CAL(&ah->iq_caldata);
INSERT_CAL(ah, &ah->iq_caldata);
ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n");
}
if (ah->supp_cals & TEMP_COMP_CAL) {
INIT_CAL(&ah->tempCompCalData);
INSERT_CAL(ah, &ah->tempCompCalData);
ath_dbg(common, CALIBRATE,
"enabling Temperature Compensation Calibration\n");
}
INIT_CAL(&ah->iq_caldata);
INSERT_CAL(ah, &ah->iq_caldata);
ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n");
/* Initialize current pointer to first element in list */
ah->cal_list_curr = ah->cal_list;

View file

@ -4586,14 +4586,14 @@ static int ar9003_hw_cal_pier_get(struct ath_hw *ah,
return 0;
}
static int ar9003_hw_power_control_override(struct ath_hw *ah,
int frequency,
int *correction,
int *voltage, int *temperature)
static void ar9003_hw_power_control_override(struct ath_hw *ah,
int frequency,
int *correction,
int *voltage, int *temperature)
{
int tempSlope = 0;
int temp_slope = 0, temp_slope1 = 0, temp_slope2 = 0;
struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
int f[8], t[8], i;
int f[8], t[8], t1[3], t2[3], i;
REG_RMW(ah, AR_PHY_TPC_11_B0,
(correction[0] << AR_PHY_TPC_OLPC_GAIN_DELTA_S),
@ -4624,38 +4624,108 @@ static int ar9003_hw_power_control_override(struct ath_hw *ah,
* enable temperature compensation
* Need to use register names
*/
if (frequency < 4000)
tempSlope = eep->modalHeader2G.tempSlope;
else if ((eep->baseEepHeader.miscConfiguration & 0x20) != 0) {
for (i = 0; i < 8; i++) {
t[i] = eep->base_ext1.tempslopextension[i];
f[i] = FBIN2FREQ(eep->calFreqPier5G[i], 0);
}
tempSlope = ar9003_hw_power_interpolate((s32) frequency,
f, t, 8);
} else if (eep->base_ext2.tempSlopeLow != 0) {
t[0] = eep->base_ext2.tempSlopeLow;
f[0] = 5180;
t[1] = eep->modalHeader5G.tempSlope;
f[1] = 5500;
t[2] = eep->base_ext2.tempSlopeHigh;
f[2] = 5785;
tempSlope = ar9003_hw_power_interpolate((s32) frequency,
f, t, 3);
} else
tempSlope = eep->modalHeader5G.tempSlope;
if (frequency < 4000) {
temp_slope = eep->modalHeader2G.tempSlope;
} else {
if (AR_SREV_9550(ah)) {
t[0] = eep->base_ext1.tempslopextension[2];
t1[0] = eep->base_ext1.tempslopextension[3];
t2[0] = eep->base_ext1.tempslopextension[4];
f[0] = 5180;
REG_RMW_FIELD(ah, AR_PHY_TPC_19, AR_PHY_TPC_19_ALPHA_THERM, tempSlope);
t[1] = eep->modalHeader5G.tempSlope;
t1[1] = eep->base_ext1.tempslopextension[0];
t2[1] = eep->base_ext1.tempslopextension[1];
f[1] = 5500;
t[2] = eep->base_ext1.tempslopextension[5];
t1[2] = eep->base_ext1.tempslopextension[6];
t2[2] = eep->base_ext1.tempslopextension[7];
f[2] = 5785;
temp_slope = ar9003_hw_power_interpolate(frequency,
f, t, 3);
temp_slope1 = ar9003_hw_power_interpolate(frequency,
f, t1, 3);
temp_slope2 = ar9003_hw_power_interpolate(frequency,
f, t2, 3);
goto tempslope;
}
if ((eep->baseEepHeader.miscConfiguration & 0x20) != 0) {
for (i = 0; i < 8; i++) {
t[i] = eep->base_ext1.tempslopextension[i];
f[i] = FBIN2FREQ(eep->calFreqPier5G[i], 0);
}
temp_slope = ar9003_hw_power_interpolate((s32) frequency,
f, t, 8);
} else if (eep->base_ext2.tempSlopeLow != 0) {
t[0] = eep->base_ext2.tempSlopeLow;
f[0] = 5180;
t[1] = eep->modalHeader5G.tempSlope;
f[1] = 5500;
t[2] = eep->base_ext2.tempSlopeHigh;
f[2] = 5785;
temp_slope = ar9003_hw_power_interpolate((s32) frequency,
f, t, 3);
} else {
temp_slope = eep->modalHeader5G.tempSlope;
}
}
tempslope:
if (AR_SREV_9550(ah)) {
/*
* AR955x has tempSlope register for each chain.
* Check whether temp_compensation feature is enabled or not.
*/
if (eep->baseEepHeader.featureEnable & 0x1) {
if (frequency < 4000) {
REG_RMW_FIELD(ah, AR_PHY_TPC_19,
AR_PHY_TPC_19_ALPHA_THERM,
eep->base_ext2.tempSlopeLow);
REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1,
AR_PHY_TPC_19_ALPHA_THERM,
temp_slope);
REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2,
AR_PHY_TPC_19_ALPHA_THERM,
eep->base_ext2.tempSlopeHigh);
} else {
REG_RMW_FIELD(ah, AR_PHY_TPC_19,
AR_PHY_TPC_19_ALPHA_THERM,
temp_slope);
REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1,
AR_PHY_TPC_19_ALPHA_THERM,
temp_slope1);
REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2,
AR_PHY_TPC_19_ALPHA_THERM,
temp_slope2);
}
} else {
/*
* If temp compensation is not enabled,
* set all registers to 0.
*/
REG_RMW_FIELD(ah, AR_PHY_TPC_19,
AR_PHY_TPC_19_ALPHA_THERM, 0);
REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1,
AR_PHY_TPC_19_ALPHA_THERM, 0);
REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2,
AR_PHY_TPC_19_ALPHA_THERM, 0);
}
} else {
REG_RMW_FIELD(ah, AR_PHY_TPC_19,
AR_PHY_TPC_19_ALPHA_THERM, temp_slope);
}
if (AR_SREV_9462_20(ah))
REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1,
AR_PHY_TPC_19_B1_ALPHA_THERM, tempSlope);
AR_PHY_TPC_19_B1_ALPHA_THERM, temp_slope);
REG_RMW_FIELD(ah, AR_PHY_TPC_18, AR_PHY_TPC_18_THERM_CAL_VALUE,
temperature[0]);
return 0;
}
/* Apply the recorded correction values. */

View file

@ -507,28 +507,59 @@ static void ar9003_tx_gain_table_mode4(struct ath_hw *ah)
else if (AR_SREV_9580(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9580_1p0_mixed_ob_db_tx_gain_table);
else
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9300Modes_mixed_ob_db_tx_gain_table_2p2);
}
static void ar9003_tx_gain_table_mode5(struct ath_hw *ah)
{
if (AR_SREV_9485_11(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9485Modes_green_ob_db_tx_gain_1_1);
else if (AR_SREV_9340(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9340Modes_ub124_tx_gain_table_1p0);
else if (AR_SREV_9580(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9580_1p0_type5_tx_gain_table);
else if (AR_SREV_9300_22(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9300Modes_type5_tx_gain_table_2p2);
}
static void ar9003_tx_gain_table_mode6(struct ath_hw *ah)
{
if (AR_SREV_9340(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9340Modes_low_ob_db_and_spur_tx_gain_table_1p0);
else if (AR_SREV_9485_11(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9485Modes_green_spur_ob_db_tx_gain_1_1);
else if (AR_SREV_9580(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9580_1p0_type6_tx_gain_table);
}
typedef void (*ath_txgain_tab)(struct ath_hw *ah);
static void ar9003_tx_gain_table_apply(struct ath_hw *ah)
{
switch (ar9003_hw_get_tx_gain_idx(ah)) {
case 0:
default:
ar9003_tx_gain_table_mode0(ah);
break;
case 1:
ar9003_tx_gain_table_mode1(ah);
break;
case 2:
ar9003_tx_gain_table_mode2(ah);
break;
case 3:
ar9003_tx_gain_table_mode3(ah);
break;
case 4:
ar9003_tx_gain_table_mode4(ah);
break;
}
static const ath_txgain_tab modes[] = {
ar9003_tx_gain_table_mode0,
ar9003_tx_gain_table_mode1,
ar9003_tx_gain_table_mode2,
ar9003_tx_gain_table_mode3,
ar9003_tx_gain_table_mode4,
ar9003_tx_gain_table_mode5,
ar9003_tx_gain_table_mode6,
};
int idx = ar9003_hw_get_tx_gain_idx(ah);
if (idx >= ARRAY_SIZE(modes))
idx = 0;
modes[idx](ah);
}
static void ar9003_rx_gain_table_mode0(struct ath_hw *ah)
@ -673,7 +704,7 @@ void ar9003_hw_attach_ops(struct ath_hw *ah)
struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
struct ath_hw_ops *ops = ath9k_hw_ops(ah);
priv_ops->init_mode_regs = ar9003_hw_init_mode_regs;
ar9003_hw_init_mode_regs(ah);
priv_ops->init_mode_gain_regs = ar9003_hw_init_mode_gain_regs;
ops->config_pci_powersave = ar9003_hw_configpcipowersave;

View file

@ -68,7 +68,7 @@ static const int m2ThreshExt_off = 127;
static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
{
u16 bMode, fracMode = 0, aModeRefSel = 0;
u32 freq, channelSel = 0, reg32 = 0;
u32 freq, chan_frac, div, channelSel = 0, reg32 = 0;
struct chan_centers centers;
int loadSynthChannel;
@ -77,9 +77,6 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
if (freq < 4800) { /* 2 GHz, fractional mode */
if (AR_SREV_9330(ah)) {
u32 chan_frac;
u32 div;
if (ah->is_clk_25mhz)
div = 75;
else
@ -89,34 +86,40 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
chan_frac = (((freq * 4) % div) * 0x20000) / div;
channelSel = (channelSel << 17) | chan_frac;
} else if (AR_SREV_9485(ah) || AR_SREV_9565(ah)) {
u32 chan_frac;
/*
* freq_ref = 40 / (refdiva >> amoderefsel); where refdiva=1 and amoderefsel=0
* freq_ref = 40 / (refdiva >> amoderefsel);
* where refdiva=1 and amoderefsel=0
* ndiv = ((chan_mhz * 4) / 3) / freq_ref;
* chansel = int(ndiv), chanfrac = (ndiv - chansel) * 0x20000
*/
channelSel = (freq * 4) / 120;
chan_frac = (((freq * 4) % 120) * 0x20000) / 120;
channelSel = (channelSel << 17) | chan_frac;
} else if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) {
} else if (AR_SREV_9340(ah)) {
if (ah->is_clk_25mhz) {
u32 chan_frac;
channelSel = (freq * 2) / 75;
chan_frac = (((freq * 2) % 75) * 0x20000) / 75;
channelSel = (channelSel << 17) | chan_frac;
} else
} else {
channelSel = CHANSEL_2G(freq) >> 1;
} else
}
} else if (AR_SREV_9550(ah)) {
if (ah->is_clk_25mhz)
div = 75;
else
div = 120;
channelSel = (freq * 4) / div;
chan_frac = (((freq * 4) % div) * 0x20000) / div;
channelSel = (channelSel << 17) | chan_frac;
} else {
channelSel = CHANSEL_2G(freq);
}
/* Set to 2G mode */
bMode = 1;
} else {
if ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) &&
ah->is_clk_25mhz) {
u32 chan_frac;
channelSel = freq / 75;
chan_frac = ((freq % 75) * 0x20000) / 75;
channelSel = (channelSel << 17) | chan_frac;
@ -586,32 +589,19 @@ static void ar9003_hw_init_bb(struct ath_hw *ah,
ath9k_hw_synth_delay(ah, chan, synthDelay);
}
static void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx)
void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx)
{
switch (rx) {
case 0x5:
if (ah->caps.tx_chainmask == 5 || ah->caps.rx_chainmask == 5)
REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
AR_PHY_SWAP_ALT_CHAIN);
case 0x3:
case 0x1:
case 0x2:
case 0x7:
REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx);
REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx);
break;
default:
break;
}
REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx);
REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx);
if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) && (tx == 0x7))
REG_WRITE(ah, AR_SELFGEN_MASK, 0x3);
else
REG_WRITE(ah, AR_SELFGEN_MASK, tx);
tx = 3;
if (tx == 0x5) {
REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
AR_PHY_SWAP_ALT_CHAIN);
}
REG_WRITE(ah, AR_SELFGEN_MASK, tx);
}
/*
@ -1450,6 +1440,67 @@ static int ar9003_hw_fast_chan_change(struct ath_hw *ah,
return 0;
}
static void ar9003_hw_spectral_scan_config(struct ath_hw *ah,
struct ath_spec_scan *param)
{
u8 count;
if (!param->enabled) {
REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN,
AR_PHY_SPECTRAL_SCAN_ENABLE);
return;
}
REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_FFT_ENA);
REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENABLE);
/* on AR93xx and newer, count = 0 will make the the chip send
* spectral samples endlessly. Check if this really was intended,
* and fix otherwise.
*/
count = param->count;
if (param->endless)
count = 0;
else if (param->count == 0)
count = 1;
if (param->short_repeat)
REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT);
else
REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN,
AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT);
REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
AR_PHY_SPECTRAL_SCAN_COUNT, count);
REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
AR_PHY_SPECTRAL_SCAN_PERIOD, param->period);
REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
AR_PHY_SPECTRAL_SCAN_FFT_PERIOD, param->fft_period);
return;
}
static void ar9003_hw_spectral_scan_trigger(struct ath_hw *ah)
{
/* Activate spectral scan */
REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
AR_PHY_SPECTRAL_SCAN_ACTIVE);
}
static void ar9003_hw_spectral_scan_wait(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
/* Poll for spectral scan complete */
if (!ath9k_hw_wait(ah, AR_PHY_SPECTRAL_SCAN,
AR_PHY_SPECTRAL_SCAN_ACTIVE,
0, AH_WAIT_TIMEOUT)) {
ath_err(common, "spectral scan wait failed\n");
return;
}
}
void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
{
struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
@ -1483,6 +1534,9 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get;
ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set;
ops->antctrl_shared_chain_lnadiv = ar9003_hw_antctrl_shared_chain_lnadiv;
ops->spectral_scan_config = ar9003_hw_spectral_scan_config;
ops->spectral_scan_trigger = ar9003_hw_spectral_scan_trigger;
ops->spectral_scan_wait = ar9003_hw_spectral_scan_wait;
ar9003_hw_set_nf_limits(ah);
ar9003_hw_set_radar_conf(ah);

View file

@ -1028,7 +1028,7 @@
#define AR_PHY_TPC_5_B2 (AR_SM2_BASE + 0x208)
#define AR_PHY_TPC_6_B2 (AR_SM2_BASE + 0x20c)
#define AR_PHY_TPC_11_B2 (AR_SM2_BASE + 0x220)
#define AR_PHY_PDADC_TAB_2 (AR_SM2_BASE + 0x240)
#define AR_PHY_TPC_19_B2 (AR_SM2_BASE + 0x240)
#define AR_PHY_TX_IQCAL_STATUS_B2 (AR_SM2_BASE + 0x48c)
#define AR_PHY_TX_IQCAL_CORR_COEFF_B2(_i) (AR_SM2_BASE + 0x450 + ((_i) << 2))

View file

@ -1172,6 +1172,106 @@ static const u32 ar9340Modes_mixed_ob_db_tx_gain_table_1p0[][5] = {
{0x00016448, 0x24925666, 0x24925666, 0x8e481266, 0x8e481266},
};
static const u32 ar9340Modes_low_ob_db_and_spur_tx_gain_table_1p0[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03eaac5a, 0x03eaac5a},
{0x0000a2e0, 0x0000f800, 0x0000f800, 0x03f330ac, 0x03f330ac},
{0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03fc3f00, 0x03fc3f00},
{0x0000a2e8, 0x00000000, 0x00000000, 0x03ffc000, 0x03ffc000},
{0x0000a394, 0x00000444, 0x00000444, 0x00000404, 0x00000404},
{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a504, 0x06000003, 0x06000003, 0x02000001, 0x02000001},
{0x0000a508, 0x0a000020, 0x0a000020, 0x05000003, 0x05000003},
{0x0000a50c, 0x10000023, 0x10000023, 0x0a000005, 0x0a000005},
{0x0000a510, 0x16000220, 0x16000220, 0x0e000201, 0x0e000201},
{0x0000a514, 0x1c000223, 0x1c000223, 0x11000203, 0x11000203},
{0x0000a518, 0x21002220, 0x21002220, 0x14000401, 0x14000401},
{0x0000a51c, 0x27002223, 0x27002223, 0x18000403, 0x18000403},
{0x0000a520, 0x2b022220, 0x2b022220, 0x1b000602, 0x1b000602},
{0x0000a524, 0x2f022222, 0x2f022222, 0x1f000802, 0x1f000802},
{0x0000a528, 0x34022225, 0x34022225, 0x21000620, 0x21000620},
{0x0000a52c, 0x3a02222a, 0x3a02222a, 0x25000820, 0x25000820},
{0x0000a530, 0x3e02222c, 0x3e02222c, 0x29000822, 0x29000822},
{0x0000a534, 0x4202242a, 0x4202242a, 0x2d000824, 0x2d000824},
{0x0000a538, 0x4702244a, 0x4702244a, 0x30000828, 0x30000828},
{0x0000a53c, 0x4b02244c, 0x4b02244c, 0x3400082a, 0x3400082a},
{0x0000a540, 0x4e02246c, 0x4e02246c, 0x38000849, 0x38000849},
{0x0000a544, 0x5302266c, 0x5302266c, 0x3b000a2c, 0x3b000a2c},
{0x0000a548, 0x5702286c, 0x5702286c, 0x3e000e2b, 0x3e000e2b},
{0x0000a54c, 0x5c02486b, 0x5c02486b, 0x42000e2d, 0x42000e2d},
{0x0000a550, 0x61024a6c, 0x61024a6c, 0x4500124a, 0x4500124a},
{0x0000a554, 0x66026a6c, 0x66026a6c, 0x4900124c, 0x4900124c},
{0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x4c00126c, 0x4c00126c},
{0x0000a55c, 0x7002708c, 0x7002708c, 0x4f00128c, 0x4f00128c},
{0x0000a560, 0x7302b08a, 0x7302b08a, 0x52001290, 0x52001290},
{0x0000a564, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292},
{0x0000a568, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292},
{0x0000a56c, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292},
{0x0000a570, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292},
{0x0000a574, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292},
{0x0000a578, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292},
{0x0000a57c, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292},
{0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
{0x0000a584, 0x06800003, 0x06800003, 0x02800001, 0x02800001},
{0x0000a588, 0x0a800020, 0x0a800020, 0x05800003, 0x05800003},
{0x0000a58c, 0x10800023, 0x10800023, 0x0a800005, 0x0a800005},
{0x0000a590, 0x16800220, 0x16800220, 0x0e800201, 0x0e800201},
{0x0000a594, 0x1c800223, 0x1c800223, 0x11800203, 0x11800203},
{0x0000a598, 0x21820220, 0x21820220, 0x14800401, 0x14800401},
{0x0000a59c, 0x27820223, 0x27820223, 0x18800403, 0x18800403},
{0x0000a5a0, 0x2b822220, 0x2b822220, 0x1b800602, 0x1b800602},
{0x0000a5a4, 0x2f822222, 0x2f822222, 0x1f800802, 0x1f800802},
{0x0000a5a8, 0x34822225, 0x34822225, 0x21800620, 0x21800620},
{0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x25800820, 0x25800820},
{0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x29800822, 0x29800822},
{0x0000a5b4, 0x4282242a, 0x4282242a, 0x2d800824, 0x2d800824},
{0x0000a5b8, 0x4782244a, 0x4782244a, 0x30800828, 0x30800828},
{0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x3480082a, 0x3480082a},
{0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x38800849, 0x38800849},
{0x0000a5c4, 0x5382266c, 0x5382266c, 0x3b800a2c, 0x3b800a2c},
{0x0000a5c8, 0x5782286c, 0x5782286c, 0x3e800e2b, 0x3e800e2b},
{0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x42800e2d, 0x42800e2d},
{0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x4580124a, 0x4580124a},
{0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x4980124c, 0x4980124c},
{0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x4c80126c, 0x4c80126c},
{0x0000a5dc, 0x7086308c, 0x7086308c, 0x4f80128c, 0x4f80128c},
{0x0000a5e0, 0x738a308a, 0x738a308a, 0x52801290, 0x52801290},
{0x0000a5e4, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292},
{0x0000a5e8, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292},
{0x0000a5ec, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292},
{0x0000a5f0, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292},
{0x0000a5f4, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292},
{0x0000a5f8, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292},
{0x0000a5fc, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292},
{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a614, 0x01404000, 0x01404000, 0x01404501, 0x01404501},
{0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501},
{0x0000a61c, 0x02008802, 0x02008802, 0x01404501, 0x01404501},
{0x0000a620, 0x0300cc03, 0x0300cc03, 0x03c0cf02, 0x03c0cf02},
{0x0000a624, 0x0300cc03, 0x0300cc03, 0x03c0cf03, 0x03c0cf03},
{0x0000a628, 0x0300cc03, 0x0300cc03, 0x04011004, 0x04011004},
{0x0000a62c, 0x03810c03, 0x03810c03, 0x05419405, 0x05419405},
{0x0000a630, 0x03810e04, 0x03810e04, 0x05419506, 0x05419506},
{0x0000a634, 0x03810e04, 0x03810e04, 0x05419506, 0x05419506},
{0x0000a638, 0x03810e04, 0x03810e04, 0x05419506, 0x05419506},
{0x0000a63c, 0x03810e04, 0x03810e04, 0x05419506, 0x05419506},
{0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03eaac5a, 0x03eaac5a},
{0x0000b2e0, 0x0000f800, 0x0000f800, 0x03f330ac, 0x03f330ac},
{0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03fc3f00, 0x03fc3f00},
{0x0000b2e8, 0x00000000, 0x00000000, 0x03ffc000, 0x03ffc000},
{0x00016044, 0x022492db, 0x022492db, 0x022492db, 0x022492db},
{0x00016048, 0x24925666, 0x24925666, 0x24925266, 0x24925266},
{0x00016280, 0x01000015, 0x01000015, 0x01001015, 0x01001015},
{0x00016288, 0xf0318000, 0xf0318000, 0xf0318000, 0xf0318000},
{0x00016444, 0x022492db, 0x022492db, 0x022492db, 0x022492db},
{0x00016448, 0x24925666, 0x24925666, 0x24925266, 0x24925266},
};
static const u32 ar9340_1p0_mac_core[][2] = {
/* Addr allmodes */
{0x00000008, 0x00000000},

View file

@ -260,6 +260,79 @@ static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = {
{0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260},
};
static const u32 ar9485Modes_green_ob_db_tx_gain_1_1[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x000098bc, 0x00000003, 0x00000003, 0x00000003, 0x00000003},
{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
{0x0000a458, 0x80000000, 0x80000000, 0x80000000, 0x80000000},
{0x0000a500, 0x00022200, 0x00022200, 0x00000006, 0x00000006},
{0x0000a504, 0x05062002, 0x05062002, 0x03000201, 0x03000201},
{0x0000a508, 0x0c002e00, 0x0c002e00, 0x06000203, 0x06000203},
{0x0000a50c, 0x11062202, 0x11062202, 0x0a000401, 0x0a000401},
{0x0000a510, 0x17022e00, 0x17022e00, 0x0e000403, 0x0e000403},
{0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x12000405, 0x12000405},
{0x0000a518, 0x25020ec0, 0x25020ec0, 0x15000604, 0x15000604},
{0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x18000605, 0x18000605},
{0x0000a520, 0x2f001f04, 0x2f001f04, 0x1c000a04, 0x1c000a04},
{0x0000a524, 0x35001fc4, 0x35001fc4, 0x21000a06, 0x21000a06},
{0x0000a528, 0x3c022f04, 0x3c022f04, 0x29000a24, 0x29000a24},
{0x0000a52c, 0x41023e85, 0x41023e85, 0x2f000e21, 0x2f000e21},
{0x0000a530, 0x48023ec6, 0x48023ec6, 0x31000e20, 0x31000e20},
{0x0000a534, 0x4d023f01, 0x4d023f01, 0x33000e20, 0x33000e20},
{0x0000a538, 0x53023f4b, 0x53023f4b, 0x43000e62, 0x43000e62},
{0x0000a53c, 0x5a027f09, 0x5a027f09, 0x45000e63, 0x45000e63},
{0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x49000e65, 0x49000e65},
{0x0000a544, 0x6502feca, 0x6502feca, 0x4b000e66, 0x4b000e66},
{0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4d001645, 0x4d001645},
{0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
{0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000b500, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
{0x0000b504, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
{0x0000b508, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
{0x0000b50c, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
{0x0000b510, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
{0x0000b514, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
{0x0000b518, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
{0x0000b51c, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
{0x0000b520, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
{0x0000b524, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
{0x0000b528, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
{0x0000b52c, 0x0000002a, 0x0000002a, 0x0000002a, 0x0000002a},
{0x0000b530, 0x0000003a, 0x0000003a, 0x0000003a, 0x0000003a},
{0x0000b534, 0x0000004a, 0x0000004a, 0x0000004a, 0x0000004a},
{0x0000b538, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b53c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b540, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b544, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b548, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b54c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b550, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b554, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b558, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b55c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b560, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b564, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b568, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b56c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b570, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b574, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b578, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b57c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db},
{0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260},
};
static const u32 ar9485Modes_high_ob_db_tx_gain_1_1[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
@ -450,6 +523,79 @@ static const u32 ar9485Modes_low_ob_db_tx_gain_1_1[][5] = {
#define ar9485_modes_lowest_ob_db_tx_gain_1_1 ar9485Modes_low_ob_db_tx_gain_1_1
static const u32 ar9485Modes_green_spur_ob_db_tx_gain_1_1[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x000098bc, 0x00000003, 0x00000003, 0x00000003, 0x00000003},
{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
{0x0000a458, 0x80000000, 0x80000000, 0x80000000, 0x80000000},
{0x0000a500, 0x00022200, 0x00022200, 0x00000006, 0x00000006},
{0x0000a504, 0x05062002, 0x05062002, 0x03000201, 0x03000201},
{0x0000a508, 0x0c002e00, 0x0c002e00, 0x07000203, 0x07000203},
{0x0000a50c, 0x11062202, 0x11062202, 0x0a000401, 0x0a000401},
{0x0000a510, 0x17022e00, 0x17022e00, 0x0e000403, 0x0e000403},
{0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x12000405, 0x12000405},
{0x0000a518, 0x25020ec0, 0x25020ec0, 0x14000406, 0x14000406},
{0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1800040a, 0x1800040a},
{0x0000a520, 0x2f001f04, 0x2f001f04, 0x1c000460, 0x1c000460},
{0x0000a524, 0x35001fc4, 0x35001fc4, 0x22000463, 0x22000463},
{0x0000a528, 0x3c022f04, 0x3c022f04, 0x26000465, 0x26000465},
{0x0000a52c, 0x41023e85, 0x41023e85, 0x2e0006e0, 0x2e0006e0},
{0x0000a530, 0x48023ec6, 0x48023ec6, 0x310006e0, 0x310006e0},
{0x0000a534, 0x4d023f01, 0x4d023f01, 0x330006e0, 0x330006e0},
{0x0000a538, 0x53023f4b, 0x53023f4b, 0x3e0008e3, 0x3e0008e3},
{0x0000a53c, 0x5a027f09, 0x5a027f09, 0x410008e5, 0x410008e5},
{0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x430008e6, 0x430008e6},
{0x0000a544, 0x6502feca, 0x6502feca, 0x4a0008ec, 0x4a0008ec},
{0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4e0008f1, 0x4e0008f1},
{0x0000a54c, 0x7203feca, 0x7203feca, 0x520008f3, 0x520008f3},
{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x54000eed, 0x54000eed},
{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x58000ef1, 0x58000ef1},
{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5c000ef3, 0x5c000ef3},
{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x60000ef5, 0x60000ef5},
{0x0000a560, 0x900fff0b, 0x900fff0b, 0x62000ef6, 0x62000ef6},
{0x0000a564, 0x960fffcb, 0x960fffcb, 0x62000ef6, 0x62000ef6},
{0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6},
{0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6},
{0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6},
{0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6},
{0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6},
{0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6},
{0x0000b500, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
{0x0000b504, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
{0x0000b508, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
{0x0000b50c, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
{0x0000b510, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
{0x0000b514, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
{0x0000b518, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
{0x0000b51c, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
{0x0000b520, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
{0x0000b524, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
{0x0000b528, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
{0x0000b52c, 0x0000002a, 0x0000002a, 0x0000002a, 0x0000002a},
{0x0000b530, 0x0000003a, 0x0000003a, 0x0000003a, 0x0000003a},
{0x0000b534, 0x0000004a, 0x0000004a, 0x0000004a, 0x0000004a},
{0x0000b538, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b53c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b540, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b544, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b548, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b54c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b550, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b554, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b558, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b55c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b560, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b564, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b568, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b56c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b570, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b574, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b578, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x0000b57c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
{0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db},
{0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260},
};
static const u32 ar9485_1_1[][2] = {
/* Addr allmodes */
{0x0000a580, 0x00000000},

View file

@ -23,16 +23,16 @@
static const u32 ar955x_1p0_radio_postamble[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x00016098, 0xd2dd5554, 0xd2dd5554, 0xd28b3330, 0xd28b3330},
{0x0001609c, 0x0a566f3a, 0x0a566f3a, 0x06345f2a, 0x06345f2a},
{0x000160ac, 0xa4647c00, 0xa4647c00, 0xa4646800, 0xa4646800},
{0x000160b0, 0x01885f52, 0x01885f52, 0x04accf3a, 0x04accf3a},
{0x00016104, 0xb7a00001, 0xb7a00001, 0xb7a00001, 0xb7a00001},
{0x0001609c, 0x0a566f3a, 0x0a566f3a, 0x0a566f3a, 0x0a566f3a},
{0x000160ac, 0xa4647c00, 0xa4647c00, 0x24647c00, 0x24647c00},
{0x000160b0, 0x01885f52, 0x01885f52, 0x01885f52, 0x01885f52},
{0x00016104, 0xb7a00000, 0xb7a00000, 0xb7a00001, 0xb7a00001},
{0x0001610c, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000},
{0x00016140, 0x10804008, 0x10804008, 0x10804008, 0x10804008},
{0x00016504, 0xb7a00001, 0xb7a00001, 0xb7a00001, 0xb7a00001},
{0x00016504, 0xb7a00000, 0xb7a00000, 0xb7a00001, 0xb7a00001},
{0x0001650c, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000},
{0x00016540, 0x10804008, 0x10804008, 0x10804008, 0x10804008},
{0x00016904, 0xb7a00001, 0xb7a00001, 0xb7a00001, 0xb7a00001},
{0x00016904, 0xb7a00000, 0xb7a00000, 0xb7a00001, 0xb7a00001},
{0x0001690c, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000},
{0x00016940, 0x10804008, 0x10804008, 0x10804008, 0x10804008},
};
@ -69,15 +69,15 @@ static const u32 ar955x_1p0_baseband_postamble[][5] = {
{0x0000a204, 0x005c0ec0, 0x005c0ec4, 0x005c0ec4, 0x005c0ec0},
{0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
{0x0000a22c, 0x07e26a2f, 0x07e26a2f, 0x01026a2f, 0x01026a2f},
{0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b},
{0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b},
{0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff},
{0x0000a238, 0xffb01018, 0xffb01018, 0xffb01018, 0xffb01018},
{0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108},
{0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898},
{0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002},
{0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e},
{0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01010e0e, 0x01010e0e},
{0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501},
{0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
{0x0000a264, 0x00000e0e, 0x00000e0e, 0x01000e0e, 0x01000e0e},
{0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b},
{0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010},
{0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},
@ -125,7 +125,7 @@ static const u32 ar955x_1p0_radio_core[][2] = {
{0x00016094, 0x00000000},
{0x000160a0, 0x0a108ffe},
{0x000160a4, 0x812fc370},
{0x000160a8, 0x423c8000},
{0x000160a8, 0x423c8100},
{0x000160b4, 0x92480080},
{0x000160c0, 0x006db6d0},
{0x000160c4, 0x6db6db60},
@ -134,7 +134,7 @@ static const u32 ar955x_1p0_radio_core[][2] = {
{0x00016100, 0x11999601},
{0x00016108, 0x00080010},
{0x00016144, 0x02084080},
{0x00016148, 0x000080c0},
{0x00016148, 0x00008040},
{0x00016280, 0x01800804},
{0x00016284, 0x00038dc5},
{0x00016288, 0x00000000},
@ -178,7 +178,7 @@ static const u32 ar955x_1p0_radio_core[][2] = {
{0x00016500, 0x11999601},
{0x00016508, 0x00080010},
{0x00016544, 0x02084080},
{0x00016548, 0x000080c0},
{0x00016548, 0x00008040},
{0x00016780, 0x00000000},
{0x00016784, 0x00000000},
{0x00016788, 0x00400705},
@ -218,7 +218,7 @@ static const u32 ar955x_1p0_radio_core[][2] = {
{0x00016900, 0x11999601},
{0x00016908, 0x00080010},
{0x00016944, 0x02084080},
{0x00016948, 0x000080c0},
{0x00016948, 0x00008040},
{0x00016b80, 0x00000000},
{0x00016b84, 0x00000000},
{0x00016b88, 0x00400705},
@ -245,9 +245,9 @@ static const u32 ar955x_1p0_radio_core[][2] = {
static const u32 ar955x_1p0_modes_xpa_tx_gain_table[][9] = {
/* Addr 5G_HT20_L 5G_HT40_L 5G_HT20_M 5G_HT40_M 5G_HT20_H 5G_HT40_H 2G_HT40 2G_HT20 */
{0x0000a2dc, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xfffd5aaa, 0xfffd5aaa},
{0x0000a2e0, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xfffe9ccc, 0xfffe9ccc},
{0x0000a2e4, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xffffe0f0, 0xffffe0f0},
{0x0000a2dc, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xfffd5aaa, 0xfffd5aaa},
{0x0000a2e0, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffe9ccc, 0xfffe9ccc},
{0x0000a2e4, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffffe0f0, 0xffffe0f0},
{0x0000a2e8, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xfffcff00, 0xfffcff00},
{0x0000a410, 0x000050de, 0x000050de, 0x000050de, 0x000050de, 0x000050de, 0x000050de, 0x000050da, 0x000050da},
{0x0000a500, 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000000, 0x00000000},
@ -256,63 +256,63 @@ static const u32 ar955x_1p0_modes_xpa_tx_gain_table[][9] = {
{0x0000a50c, 0x0c00000b, 0x0c00000b, 0x0c00000b, 0x0c00000b, 0x0c00000b, 0x0c00000b, 0x0c000006, 0x0c000006},
{0x0000a510, 0x1000000d, 0x1000000d, 0x1000000d, 0x1000000d, 0x1000000d, 0x1000000d, 0x0f00000a, 0x0f00000a},
{0x0000a514, 0x14000011, 0x14000011, 0x14000011, 0x14000011, 0x14000011, 0x14000011, 0x1300000c, 0x1300000c},
{0x0000a518, 0x19004008, 0x19004008, 0x19004008, 0x19004008, 0x18004008, 0x18004008, 0x1700000e, 0x1700000e},
{0x0000a51c, 0x1d00400a, 0x1d00400a, 0x1d00400a, 0x1d00400a, 0x1c00400a, 0x1c00400a, 0x1b000064, 0x1b000064},
{0x0000a520, 0x230020a2, 0x230020a2, 0x210020a2, 0x210020a2, 0x200020a2, 0x200020a2, 0x1f000242, 0x1f000242},
{0x0000a524, 0x2500006e, 0x2500006e, 0x2500006e, 0x2500006e, 0x2400006e, 0x2400006e, 0x23000229, 0x23000229},
{0x0000a528, 0x29022221, 0x29022221, 0x28022221, 0x28022221, 0x27022221, 0x27022221, 0x270002a2, 0x270002a2},
{0x0000a52c, 0x2d00062a, 0x2d00062a, 0x2c00062a, 0x2c00062a, 0x2a00062a, 0x2a00062a, 0x2c001203, 0x2c001203},
{0x0000a530, 0x340220a5, 0x340220a5, 0x320220a5, 0x320220a5, 0x2f0220a5, 0x2f0220a5, 0x30001803, 0x30001803},
{0x0000a534, 0x380022c5, 0x380022c5, 0x350022c5, 0x350022c5, 0x320022c5, 0x320022c5, 0x33000881, 0x33000881},
{0x0000a538, 0x3b002486, 0x3b002486, 0x39002486, 0x39002486, 0x36002486, 0x36002486, 0x38001809, 0x38001809},
{0x0000a53c, 0x3f00248a, 0x3f00248a, 0x3d00248a, 0x3d00248a, 0x3a00248a, 0x3a00248a, 0x3a000814, 0x3a000814},
{0x0000a540, 0x4202242c, 0x4202242c, 0x4102242c, 0x4102242c, 0x3f02242c, 0x3f02242c, 0x3f001a0c, 0x3f001a0c},
{0x0000a544, 0x490044c6, 0x490044c6, 0x460044c6, 0x460044c6, 0x420044c6, 0x420044c6, 0x43001a0e, 0x43001a0e},
{0x0000a548, 0x4d024485, 0x4d024485, 0x4a024485, 0x4a024485, 0x46024485, 0x46024485, 0x46001812, 0x46001812},
{0x0000a54c, 0x51044483, 0x51044483, 0x4e044483, 0x4e044483, 0x4a044483, 0x4a044483, 0x49001884, 0x49001884},
{0x0000a550, 0x5404a40c, 0x5404a40c, 0x5204a40c, 0x5204a40c, 0x4d04a40c, 0x4d04a40c, 0x4d001e84, 0x4d001e84},
{0x0000a554, 0x57024632, 0x57024632, 0x55024632, 0x55024632, 0x52024632, 0x52024632, 0x50001e69, 0x50001e69},
{0x0000a558, 0x5c00a634, 0x5c00a634, 0x5900a634, 0x5900a634, 0x5600a634, 0x5600a634, 0x550006f4, 0x550006f4},
{0x0000a55c, 0x5f026832, 0x5f026832, 0x5d026832, 0x5d026832, 0x5a026832, 0x5a026832, 0x59000ad3, 0x59000ad3},
{0x0000a560, 0x6602b012, 0x6602b012, 0x6202b012, 0x6202b012, 0x5d02b012, 0x5d02b012, 0x5e000ad5, 0x5e000ad5},
{0x0000a564, 0x6e02d0e1, 0x6e02d0e1, 0x6802d0e1, 0x6802d0e1, 0x6002d0e1, 0x6002d0e1, 0x61001ced, 0x61001ced},
{0x0000a568, 0x7202b4c4, 0x7202b4c4, 0x6c02b4c4, 0x6c02b4c4, 0x6502b4c4, 0x6502b4c4, 0x660018d4, 0x660018d4},
{0x0000a56c, 0x75007894, 0x75007894, 0x70007894, 0x70007894, 0x6b007894, 0x6b007894, 0x660018d4, 0x660018d4},
{0x0000a570, 0x7b025c74, 0x7b025c74, 0x75025c74, 0x75025c74, 0x70025c74, 0x70025c74, 0x660018d4, 0x660018d4},
{0x0000a574, 0x8300bcb5, 0x8300bcb5, 0x7a00bcb5, 0x7a00bcb5, 0x7600bcb5, 0x7600bcb5, 0x660018d4, 0x660018d4},
{0x0000a578, 0x8a04dc74, 0x8a04dc74, 0x7f04dc74, 0x7f04dc74, 0x7c04dc74, 0x7c04dc74, 0x660018d4, 0x660018d4},
{0x0000a57c, 0x8a04dc74, 0x8a04dc74, 0x7f04dc74, 0x7f04dc74, 0x7c04dc74, 0x7c04dc74, 0x660018d4, 0x660018d4},
{0x0000a518, 0x1700002b, 0x1700002b, 0x1700002b, 0x1700002b, 0x1600002b, 0x1600002b, 0x1700000e, 0x1700000e},
{0x0000a51c, 0x1b00002d, 0x1b00002d, 0x1b00002d, 0x1b00002d, 0x1a00002d, 0x1a00002d, 0x1b000064, 0x1b000064},
{0x0000a520, 0x20000031, 0x20000031, 0x1f000031, 0x1f000031, 0x1e000031, 0x1e000031, 0x1f000242, 0x1f000242},
{0x0000a524, 0x24000051, 0x24000051, 0x23000051, 0x23000051, 0x23000051, 0x23000051, 0x23000229, 0x23000229},
{0x0000a528, 0x27000071, 0x27000071, 0x27000071, 0x27000071, 0x26000071, 0x26000071, 0x270002a2, 0x270002a2},
{0x0000a52c, 0x2b000092, 0x2b000092, 0x2b000092, 0x2b000092, 0x2b000092, 0x2b000092, 0x2c001203, 0x2c001203},
{0x0000a530, 0x3000028c, 0x3000028c, 0x2f00028c, 0x2f00028c, 0x2e00028c, 0x2e00028c, 0x30001803, 0x30001803},
{0x0000a534, 0x34000290, 0x34000290, 0x33000290, 0x33000290, 0x32000290, 0x32000290, 0x33000881, 0x33000881},
{0x0000a538, 0x37000292, 0x37000292, 0x36000292, 0x36000292, 0x35000292, 0x35000292, 0x38001809, 0x38001809},
{0x0000a53c, 0x3b02028d, 0x3b02028d, 0x3a02028d, 0x3a02028d, 0x3902028d, 0x3902028d, 0x3a000814, 0x3a000814},
{0x0000a540, 0x3f020291, 0x3f020291, 0x3e020291, 0x3e020291, 0x3d020291, 0x3d020291, 0x3f001a0c, 0x3f001a0c},
{0x0000a544, 0x44020490, 0x44020490, 0x43020490, 0x43020490, 0x42020490, 0x42020490, 0x43001a0e, 0x43001a0e},
{0x0000a548, 0x48020492, 0x48020492, 0x47020492, 0x47020492, 0x46020492, 0x46020492, 0x46001812, 0x46001812},
{0x0000a54c, 0x4c020692, 0x4c020692, 0x4b020692, 0x4b020692, 0x4a020692, 0x4a020692, 0x49001884, 0x49001884},
{0x0000a550, 0x50020892, 0x50020892, 0x4f020892, 0x4f020892, 0x4e020892, 0x4e020892, 0x4d001e84, 0x4d001e84},
{0x0000a554, 0x53040891, 0x53040891, 0x53040891, 0x53040891, 0x52040891, 0x52040891, 0x50001e69, 0x50001e69},
{0x0000a558, 0x58040893, 0x58040893, 0x57040893, 0x57040893, 0x56040893, 0x56040893, 0x550006f4, 0x550006f4},
{0x0000a55c, 0x5c0408b4, 0x5c0408b4, 0x5a0408b4, 0x5a0408b4, 0x5a0408b4, 0x5a0408b4, 0x59000ad3, 0x59000ad3},
{0x0000a560, 0x610408b6, 0x610408b6, 0x5e0408b6, 0x5e0408b6, 0x5e0408b6, 0x5e0408b6, 0x5e000ad5, 0x5e000ad5},
{0x0000a564, 0x670408f6, 0x670408f6, 0x620408f6, 0x620408f6, 0x620408f6, 0x620408f6, 0x61001ced, 0x61001ced},
{0x0000a568, 0x6a040cf6, 0x6a040cf6, 0x66040cf6, 0x66040cf6, 0x66040cf6, 0x66040cf6, 0x660018d4, 0x660018d4},
{0x0000a56c, 0x6d040d76, 0x6d040d76, 0x6a040d76, 0x6a040d76, 0x6a040d76, 0x6a040d76, 0x660018d4, 0x660018d4},
{0x0000a570, 0x70060db6, 0x70060db6, 0x6e060db6, 0x6e060db6, 0x6e060db6, 0x6e060db6, 0x660018d4, 0x660018d4},
{0x0000a574, 0x730a0df6, 0x730a0df6, 0x720a0df6, 0x720a0df6, 0x720a0df6, 0x720a0df6, 0x660018d4, 0x660018d4},
{0x0000a578, 0x770a13f6, 0x770a13f6, 0x760a13f6, 0x760a13f6, 0x760a13f6, 0x760a13f6, 0x660018d4, 0x660018d4},
{0x0000a57c, 0x770a13f6, 0x770a13f6, 0x760a13f6, 0x760a13f6, 0x760a13f6, 0x760a13f6, 0x660018d4, 0x660018d4},
{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x03804000, 0x03804000},
{0x0000a610, 0x04c08c01, 0x04c08c01, 0x04808b01, 0x04808b01, 0x04808a01, 0x04808a01, 0x0300ca02, 0x0300ca02},
{0x0000a614, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00000e04, 0x00000e04},
{0x0000a618, 0x04010c01, 0x04010c01, 0x03c10b01, 0x03c10b01, 0x03810a01, 0x03810a01, 0x03014000, 0x03014000},
{0x0000a61c, 0x03814e05, 0x03814e05, 0x03414d05, 0x03414d05, 0x03414d05, 0x03414d05, 0x00000000, 0x00000000},
{0x0000a620, 0x04010303, 0x04010303, 0x03c10303, 0x03c10303, 0x03810303, 0x03810303, 0x00000000, 0x00000000},
{0x0000a624, 0x03814e05, 0x03814e05, 0x03414d05, 0x03414d05, 0x03414d05, 0x03414d05, 0x03014000, 0x03014000},
{0x0000a628, 0x00c0c000, 0x00c0c000, 0x00c0c000, 0x00c0c000, 0x00c0c000, 0x00c0c000, 0x03804c05, 0x03804c05},
{0x0000a62c, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x0701de06, 0x0701de06},
{0x0000a630, 0x03418000, 0x03418000, 0x03018000, 0x03018000, 0x02c18000, 0x02c18000, 0x07819c07, 0x07819c07},
{0x0000a634, 0x03815004, 0x03815004, 0x03414f04, 0x03414f04, 0x03414e04, 0x03414e04, 0x0701dc07, 0x0701dc07},
{0x0000a638, 0x03005302, 0x03005302, 0x02c05202, 0x02c05202, 0x02805202, 0x02805202, 0x0701dc07, 0x0701dc07},
{0x0000a63c, 0x04c09302, 0x04c09302, 0x04809202, 0x04809202, 0x04809202, 0x04809202, 0x0701dc07, 0x0701dc07},
{0x0000b2dc, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xfffd5aaa, 0xfffd5aaa},
{0x0000b2e0, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xfffe9ccc, 0xfffe9ccc},
{0x0000b2e4, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xffffe0f0, 0xffffe0f0},
{0x0000a60c, 0x02c04b01, 0x02c04b01, 0x02c04b01, 0x02c04b01, 0x02c04b01, 0x02c04b01, 0x03804000, 0x03804000},
{0x0000a610, 0x04008b01, 0x04008b01, 0x04008b01, 0x04008b01, 0x03c08b01, 0x03c08b01, 0x0300ca02, 0x0300ca02},
{0x0000a614, 0x05811403, 0x05811403, 0x05411303, 0x05411303, 0x05411303, 0x05411303, 0x00000e04, 0x00000e04},
{0x0000a618, 0x05811604, 0x05811604, 0x05411504, 0x05411504, 0x05411504, 0x05411504, 0x03014000, 0x03014000},
{0x0000a61c, 0x05811604, 0x05811604, 0x05411504, 0x05411504, 0x05411504, 0x05411504, 0x00000000, 0x00000000},
{0x0000a620, 0x05811604, 0x05811604, 0x05411504, 0x05411504, 0x05411504, 0x05411504, 0x00000000, 0x00000000},
{0x0000a624, 0x05811604, 0x05811604, 0x05411504, 0x05411504, 0x05411504, 0x05411504, 0x03014000, 0x03014000},
{0x0000a628, 0x05811604, 0x05811604, 0x05411504, 0x05411504, 0x05411504, 0x05411504, 0x03804c05, 0x03804c05},
{0x0000a62c, 0x06815604, 0x06815604, 0x06415504, 0x06415504, 0x06015504, 0x06015504, 0x0701de06, 0x0701de06},
{0x0000a630, 0x07819a05, 0x07819a05, 0x07419905, 0x07419905, 0x07019805, 0x07019805, 0x07819c07, 0x07819c07},
{0x0000a634, 0x07819e06, 0x07819e06, 0x07419d06, 0x07419d06, 0x07019c06, 0x07019c06, 0x0701dc07, 0x0701dc07},
{0x0000a638, 0x07819e06, 0x07819e06, 0x07419d06, 0x07419d06, 0x07019c06, 0x07019c06, 0x0701dc07, 0x0701dc07},
{0x0000a63c, 0x07819e06, 0x07819e06, 0x07419d06, 0x07419d06, 0x07019c06, 0x07019c06, 0x0701dc07, 0x0701dc07},
{0x0000b2dc, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xfffd5aaa, 0xfffd5aaa},
{0x0000b2e0, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffe9ccc, 0xfffe9ccc},
{0x0000b2e4, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffffe0f0, 0xffffe0f0},
{0x0000b2e8, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xfffcff00, 0xfffcff00},
{0x0000c2dc, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xfffd5aaa, 0xfffd5aaa},
{0x0000c2e0, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xfffe9ccc, 0xfffe9ccc},
{0x0000c2e4, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xffffe0f0, 0xffffe0f0},
{0x0000c2dc, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xfffd5aaa, 0xfffd5aaa},
{0x0000c2e0, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffe9ccc, 0xfffe9ccc},
{0x0000c2e4, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffffe0f0, 0xffffe0f0},
{0x0000c2e8, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xfffcff00, 0xfffcff00},
{0x00016044, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x010002d4, 0x010002d4},
{0x00016048, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x66482401, 0x66482401},
{0x00016048, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401},
{0x00016280, 0x01801e84, 0x01801e84, 0x01801e84, 0x01801e84, 0x01801e84, 0x01801e84, 0x01808e84, 0x01808e84},
{0x00016444, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x010002d4, 0x010002d4},
{0x00016448, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x66482401, 0x66482401},
{0x00016448, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401},
{0x00016844, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x010002d4, 0x010002d4},
{0x00016848, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x66482401, 0x66482401},
{0x00016848, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401},
};
static const u32 ar955x_1p0_mac_core[][2] = {
@ -846,7 +846,7 @@ static const u32 ar955x_1p0_baseband_core[][2] = {
{0x0000a44c, 0x00000001},
{0x0000a450, 0x00010000},
{0x0000a458, 0x00000000},
{0x0000a644, 0x3fad9d74},
{0x0000a644, 0xbfad9d74},
{0x0000a648, 0x0048060a},
{0x0000a64c, 0x00003c37},
{0x0000a670, 0x03020100},
@ -1277,7 +1277,7 @@ static const u32 ar955x_1p0_modes_fast_clock[][3] = {
{0x0000801c, 0x148ec02b, 0x148ec057},
{0x00008318, 0x000044c0, 0x00008980},
{0x00009e00, 0x0372131c, 0x0372131c},
{0x0000a230, 0x0000000b, 0x00000016},
{0x0000a230, 0x0000400b, 0x00004016},
{0x0000a254, 0x00000898, 0x00001130},
};

View file

@ -685,6 +685,82 @@ static const u32 ar9580_1p0_mixed_ob_db_tx_gain_table[][5] = {
#define ar9580_1p0_high_ob_db_tx_gain_table ar9300Modes_high_ob_db_tx_gain_table_2p2
#define ar9580_1p0_type5_tx_gain_table ar9300Modes_type5_tx_gain_table_2p2
static const u32 ar9580_1p0_type6_tx_gain_table[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x0000a2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
{0x0000a2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
{0x0000a2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
{0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
{0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
{0x0000a510, 0x15000028, 0x15000028, 0x0f000202, 0x0f000202},
{0x0000a514, 0x1b00002b, 0x1b00002b, 0x12000400, 0x12000400},
{0x0000a518, 0x1f020028, 0x1f020028, 0x16000402, 0x16000402},
{0x0000a51c, 0x2502002b, 0x2502002b, 0x19000404, 0x19000404},
{0x0000a520, 0x2a04002a, 0x2a04002a, 0x1c000603, 0x1c000603},
{0x0000a524, 0x2e06002a, 0x2e06002a, 0x21000a02, 0x21000a02},
{0x0000a528, 0x3302202d, 0x3302202d, 0x25000a04, 0x25000a04},
{0x0000a52c, 0x3804202c, 0x3804202c, 0x28000a20, 0x28000a20},
{0x0000a530, 0x3c06202c, 0x3c06202c, 0x2c000e20, 0x2c000e20},
{0x0000a534, 0x4108202d, 0x4108202d, 0x30000e22, 0x30000e22},
{0x0000a538, 0x4506402d, 0x4506402d, 0x34000e24, 0x34000e24},
{0x0000a53c, 0x4906222d, 0x4906222d, 0x38001640, 0x38001640},
{0x0000a540, 0x4d062231, 0x4d062231, 0x3c001660, 0x3c001660},
{0x0000a544, 0x50082231, 0x50082231, 0x3f001861, 0x3f001861},
{0x0000a548, 0x5608422e, 0x5608422e, 0x43001a81, 0x43001a81},
{0x0000a54c, 0x5e08442e, 0x5e08442e, 0x47001a83, 0x47001a83},
{0x0000a550, 0x620a4431, 0x620a4431, 0x4a001c84, 0x4a001c84},
{0x0000a554, 0x640a4432, 0x640a4432, 0x4e001ce3, 0x4e001ce3},
{0x0000a558, 0x680a4434, 0x680a4434, 0x52001ce5, 0x52001ce5},
{0x0000a55c, 0x6c0a6434, 0x6c0a6434, 0x56001ce9, 0x56001ce9},
{0x0000a560, 0x6f0a6633, 0x6f0a6633, 0x5a001ceb, 0x5a001ceb},
{0x0000a564, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
{0x0000a568, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
{0x0000a56c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
{0x0000a570, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
{0x0000a574, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
{0x0000a578, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
{0x0000a57c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a608, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
{0x0000a60c, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
{0x0000a610, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
{0x0000a614, 0x01804601, 0x01804601, 0x01404000, 0x01404000},
{0x0000a618, 0x01804601, 0x01804601, 0x01404501, 0x01404501},
{0x0000a61c, 0x01804601, 0x01804601, 0x02008501, 0x02008501},
{0x0000a620, 0x03408d02, 0x03408d02, 0x0280ca03, 0x0280ca03},
{0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04},
{0x0000a628, 0x03410d04, 0x03410d04, 0x04014c04, 0x04014c04},
{0x0000a62c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
{0x0000a630, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
{0x0000a634, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
{0x0000a638, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
{0x0000a63c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
{0x0000b2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
{0x0000b2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
{0x0000b2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x0000c2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
{0x0000c2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
{0x0000c2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
{0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
{0x00016048, 0x61200001, 0x61200001, 0x66480001, 0x66480001},
{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
{0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
{0x00016448, 0x61200001, 0x61200001, 0x66480001, 0x66480001},
{0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
{0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
{0x00016848, 0x61200001, 0x61200001, 0x66480001, 0x66480001},
{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
};
static const u32 ar9580_1p0_soc_preamble[][2] = {
/* Addr allmodes */
{0x000040a4, 0x00a0c1c9},

View file

@ -109,14 +109,11 @@ struct ath_descdma {
void *dd_desc;
dma_addr_t dd_desc_paddr;
u32 dd_desc_len;
struct ath_buf *dd_bufptr;
};
int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
struct list_head *head, const char *name,
int nbuf, int ndesc, bool is_tx);
void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
struct list_head *head);
/***********/
/* RX / TX */
@ -317,10 +314,8 @@ struct ath_rx {
u32 *rxlink;
u32 num_pkts;
unsigned int rxfilter;
spinlock_t rxbuflock;
struct list_head rxbuf;
struct ath_descdma rxdma;
struct ath_buf *rx_bufptr;
struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX];
struct sk_buff *frag;
@ -328,7 +323,6 @@ struct ath_rx {
int ath_startrecv(struct ath_softc *sc);
bool ath_stoprecv(struct ath_softc *sc);
void ath_flushrecv(struct ath_softc *sc);
u32 ath_calcrxfilter(struct ath_softc *sc);
int ath_rx_init(struct ath_softc *sc, int nbufs);
void ath_rx_cleanup(struct ath_softc *sc);
@ -338,14 +332,12 @@ void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq);
void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq);
void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq);
void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq);
bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx);
void ath_draintxq(struct ath_softc *sc,
struct ath_txq *txq, bool retry_tx);
bool ath_drain_all_txq(struct ath_softc *sc);
void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq);
void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an);
void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an);
void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq);
int ath_tx_init(struct ath_softc *sc, int nbufs);
void ath_tx_cleanup(struct ath_softc *sc);
int ath_txq_update(struct ath_softc *sc, int qnum,
struct ath9k_tx_queue_info *q);
void ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop);
@ -646,7 +638,6 @@ void ath_ant_comb_update(struct ath_softc *sc);
enum sc_op_flags {
SC_OP_INVALID,
SC_OP_BEACONS,
SC_OP_RXFLUSH,
SC_OP_ANI_RUN,
SC_OP_PRIM_STA_VIF,
SC_OP_HW_RESET,
@ -675,6 +666,23 @@ struct ath9k_vif_iter_data {
int nadhocs; /* number of adhoc vifs */
};
/* enum spectral_mode:
*
* @SPECTRAL_DISABLED: spectral mode is disabled
* @SPECTRAL_BACKGROUND: hardware sends samples when it is not busy with
* something else.
* @SPECTRAL_MANUAL: spectral scan is enabled, triggering for samples
* is performed manually.
* @SPECTRAL_CHANSCAN: Like manual, but also triggered when changing channels
* during a channel scan.
*/
enum spectral_mode {
SPECTRAL_DISABLED = 0,
SPECTRAL_BACKGROUND,
SPECTRAL_MANUAL,
SPECTRAL_CHANSCAN,
};
struct ath_softc {
struct ieee80211_hw *hw;
struct device *dev;
@ -743,6 +751,10 @@ struct ath_softc {
u8 ant_tx, ant_rx;
struct dfs_pattern_detector *dfs_detector;
u32 wow_enabled;
/* relay(fs) channel for spectral scan */
struct rchan *rfs_chan_spec_scan;
enum spectral_mode spectral_mode;
int scanning;
#ifdef CONFIG_PM_SLEEP
atomic_t wow_got_bmiss_intr;
@ -751,6 +763,133 @@ struct ath_softc {
#endif
};
#define SPECTRAL_SCAN_BITMASK 0x10
/* Radar info packet format, used for DFS and spectral formats. */
struct ath_radar_info {
u8 pulse_length_pri;
u8 pulse_length_ext;
u8 pulse_bw_info;
} __packed;
/* The HT20 spectral data has 4 bytes of additional information at it's end.
*
* [7:0]: all bins {max_magnitude[1:0], bitmap_weight[5:0]}
* [7:0]: all bins max_magnitude[9:2]
* [7:0]: all bins {max_index[5:0], max_magnitude[11:10]}
* [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned)
*/
struct ath_ht20_mag_info {
u8 all_bins[3];
u8 max_exp;
} __packed;
#define SPECTRAL_HT20_NUM_BINS 56
/* WARNING: don't actually use this struct! MAC may vary the amount of
* data by -1/+2. This struct is for reference only.
*/
struct ath_ht20_fft_packet {
u8 data[SPECTRAL_HT20_NUM_BINS];
struct ath_ht20_mag_info mag_info;
struct ath_radar_info radar_info;
} __packed;
#define SPECTRAL_HT20_TOTAL_DATA_LEN (sizeof(struct ath_ht20_fft_packet))
/* Dynamic 20/40 mode:
*
* [7:0]: lower bins {max_magnitude[1:0], bitmap_weight[5:0]}
* [7:0]: lower bins max_magnitude[9:2]
* [7:0]: lower bins {max_index[5:0], max_magnitude[11:10]}
* [7:0]: upper bins {max_magnitude[1:0], bitmap_weight[5:0]}
* [7:0]: upper bins max_magnitude[9:2]
* [7:0]: upper bins {max_index[5:0], max_magnitude[11:10]}
* [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned)
*/
struct ath_ht20_40_mag_info {
u8 lower_bins[3];
u8 upper_bins[3];
u8 max_exp;
} __packed;
#define SPECTRAL_HT20_40_NUM_BINS 128
/* WARNING: don't actually use this struct! MAC may vary the amount of
* data. This struct is for reference only.
*/
struct ath_ht20_40_fft_packet {
u8 data[SPECTRAL_HT20_40_NUM_BINS];
struct ath_ht20_40_mag_info mag_info;
struct ath_radar_info radar_info;
} __packed;
#define SPECTRAL_HT20_40_TOTAL_DATA_LEN (sizeof(struct ath_ht20_40_fft_packet))
/* grabs the max magnitude from the all/upper/lower bins */
static inline u16 spectral_max_magnitude(u8 *bins)
{
return (bins[0] & 0xc0) >> 6 |
(bins[1] & 0xff) << 2 |
(bins[2] & 0x03) << 10;
}
/* return the max magnitude from the all/upper/lower bins */
static inline u8 spectral_max_index(u8 *bins)
{
s8 m = (bins[2] & 0xfc) >> 2;
/* TODO: this still doesn't always report the right values ... */
if (m > 32)
m |= 0xe0;
else
m &= ~0xe0;
return m + 29;
}
/* return the bitmap weight from the all/upper/lower bins */
static inline u8 spectral_bitmap_weight(u8 *bins)
{
return bins[0] & 0x3f;
}
/* FFT sample format given to userspace via debugfs.
*
* Please keep the type/length at the front position and change
* other fields after adding another sample type
*
* TODO: this might need rework when switching to nl80211-based
* interface.
*/
enum ath_fft_sample_type {
ATH_FFT_SAMPLE_HT20 = 0,
};
struct fft_sample_tlv {
u8 type; /* see ath_fft_sample */
u16 length;
/* type dependent data follows */
} __packed;
struct fft_sample_ht20 {
struct fft_sample_tlv tlv;
u8 __alignment;
u16 freq;
s8 rssi;
s8 noise;
u16 max_magnitude;
u8 max_index;
u8 bitmap_weight;
u64 tsf;
u16 data[SPECTRAL_HT20_NUM_BINS];
} __packed;
void ath9k_tasklet(unsigned long data);
int ath_cabq_update(struct ath_softc *);
@ -773,6 +912,10 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw);
void ath9k_reload_chainmask_settings(struct ath_softc *sc);
bool ath9k_uses_beacons(int type);
void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw);
int ath9k_spectral_scan_config(struct ieee80211_hw *hw,
enum spectral_mode spectral_mode);
#ifdef CONFIG_ATH9K_PCI
int ath_pci_init(void);

View file

@ -147,6 +147,7 @@ static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw,
skb->len, DMA_TO_DEVICE);
dev_kfree_skb_any(skb);
bf->bf_buf_addr = 0;
bf->bf_mpdu = NULL;
}
skb = ieee80211_beacon_get(hw, vif);
@ -198,7 +199,7 @@ static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw,
if (sc->nvifs > 1) {
ath_dbg(common, BEACON,
"Flushing previous cabq traffic\n");
ath_draintxq(sc, cabq, false);
ath_draintxq(sc, cabq);
}
}
@ -359,7 +360,6 @@ void ath9k_beacon_tasklet(unsigned long data)
return;
bf = ath9k_beacon_generate(sc->hw, vif);
WARN_ON(!bf);
if (sc->beacon.bmisscnt != 0) {
ath_dbg(common, BSTUCK, "resume beacon xmit after %u misses\n",

View file

@ -17,6 +17,7 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/export.h>
#include <linux/relay.h>
#include <asm/unaligned.h>
#include "ath9k.h"
@ -861,7 +862,6 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
RXS_ERR("RX-LENGTH-ERR", rx_len_err);
RXS_ERR("RX-OOM-ERR", rx_oom_err);
RXS_ERR("RX-RATE-ERR", rx_rate_err);
RXS_ERR("RX-DROP-RXFLUSH", rx_drop_rxflush);
RXS_ERR("RX-TOO-MANY-FRAGS", rx_too_many_frags_err);
PHY_ERR("UNDERRUN ERR", ATH9K_PHYERR_UNDERRUN);
@ -966,6 +966,112 @@ static const struct file_operations fops_recv = {
.llseek = default_llseek,
};
static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
char *mode = "";
unsigned int len;
switch (sc->spectral_mode) {
case SPECTRAL_DISABLED:
mode = "disable";
break;
case SPECTRAL_BACKGROUND:
mode = "background";
break;
case SPECTRAL_CHANSCAN:
mode = "chanscan";
break;
case SPECTRAL_MANUAL:
mode = "manual";
break;
}
len = strlen(mode);
return simple_read_from_buffer(user_buf, count, ppos, mode, len);
}
static ssize_t write_file_spec_scan_ctl(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
char buf[32];
ssize_t len;
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
buf[len] = '\0';
if (strncmp("trigger", buf, 7) == 0) {
ath9k_spectral_scan_trigger(sc->hw);
} else if (strncmp("background", buf, 9) == 0) {
ath9k_spectral_scan_config(sc->hw, SPECTRAL_BACKGROUND);
ath_dbg(common, CONFIG, "spectral scan: background mode enabled\n");
} else if (strncmp("chanscan", buf, 8) == 0) {
ath9k_spectral_scan_config(sc->hw, SPECTRAL_CHANSCAN);
ath_dbg(common, CONFIG, "spectral scan: channel scan mode enabled\n");
} else if (strncmp("manual", buf, 6) == 0) {
ath9k_spectral_scan_config(sc->hw, SPECTRAL_MANUAL);
ath_dbg(common, CONFIG, "spectral scan: manual mode enabled\n");
} else if (strncmp("disable", buf, 7) == 0) {
ath9k_spectral_scan_config(sc->hw, SPECTRAL_DISABLED);
ath_dbg(common, CONFIG, "spectral scan: disabled\n");
} else {
return -EINVAL;
}
return count;
}
static const struct file_operations fops_spec_scan_ctl = {
.read = read_file_spec_scan_ctl,
.write = write_file_spec_scan_ctl,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static struct dentry *create_buf_file_handler(const char *filename,
struct dentry *parent,
umode_t mode,
struct rchan_buf *buf,
int *is_global)
{
struct dentry *buf_file;
buf_file = debugfs_create_file(filename, mode, parent, buf,
&relay_file_operations);
*is_global = 1;
return buf_file;
}
static int remove_buf_file_handler(struct dentry *dentry)
{
debugfs_remove(dentry);
return 0;
}
void ath_debug_send_fft_sample(struct ath_softc *sc,
struct fft_sample_tlv *fft_sample_tlv)
{
if (!sc->rfs_chan_spec_scan)
return;
relay_write(sc->rfs_chan_spec_scan, fft_sample_tlv,
fft_sample_tlv->length + sizeof(*fft_sample_tlv));
}
static struct rchan_callbacks rfs_spec_scan_cb = {
.create_buf_file = create_buf_file_handler,
.remove_buf_file = remove_buf_file_handler,
};
static ssize_t read_file_regidx(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
@ -1780,6 +1886,14 @@ int ath9k_init_debug(struct ath_hw *ah)
&fops_base_eeprom);
debugfs_create_file("modal_eeprom", S_IRUSR, sc->debug.debugfs_phy, sc,
&fops_modal_eeprom);
sc->rfs_chan_spec_scan = relay_open("spectral_scan",
sc->debug.debugfs_phy,
262144, 4, &rfs_spec_scan_cb,
NULL);
debugfs_create_file("spectral_scan_ctl", S_IRUSR | S_IWUSR,
sc->debug.debugfs_phy, sc,
&fops_spec_scan_ctl);
#ifdef CONFIG_ATH9K_MAC_DEBUG
debugfs_create_file("samples", S_IRUSR, sc->debug.debugfs_phy, sc,
&fops_samps);

View file

@ -23,6 +23,7 @@
struct ath_txq;
struct ath_buf;
struct fft_sample_tlv;
#ifdef CONFIG_ATH9K_DEBUGFS
#define TX_STAT_INC(q, c) sc->debug.stats.txstats[q].c++
@ -216,7 +217,6 @@ struct ath_tx_stats {
* @rx_oom_err: No. of frames dropped due to OOM issues.
* @rx_rate_err: No. of frames dropped due to rate errors.
* @rx_too_many_frags_err: Frames dropped due to too-many-frags received.
* @rx_drop_rxflush: No. of frames dropped due to RX-FLUSH.
* @rx_beacons: No. of beacons received.
* @rx_frags: No. of rx-fragements received.
*/
@ -235,7 +235,6 @@ struct ath_rx_stats {
u32 rx_oom_err;
u32 rx_rate_err;
u32 rx_too_many_frags_err;
u32 rx_drop_rxflush;
u32 rx_beacons;
u32 rx_frags;
};
@ -323,6 +322,10 @@ void ath9k_sta_remove_debugfs(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct dentry *dir);
void ath_debug_send_fft_sample(struct ath_softc *sc,
struct fft_sample_tlv *fft_sample);
#else
#define RX_STAT_INC(c) /* NOP */

View file

@ -280,14 +280,14 @@ static int ath9k_init_htc_services(struct ath9k_htc_priv *priv, u16 devid,
return ret;
}
static int ath9k_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
static void ath9k_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
{
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct ath9k_htc_priv *priv = hw->priv;
return ath_reg_notifier_apply(wiphy, request,
ath9k_hw_regulatory(priv->ah));
ath_reg_notifier_apply(wiphy, request,
ath9k_hw_regulatory(priv->ah));
}
static unsigned int ath9k_regread(void *hw_priv, u32 reg_offset)

View file

@ -1628,7 +1628,9 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
if (!ret)
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
case IEEE80211_AMPDU_TX_STOP:
case IEEE80211_AMPDU_TX_STOP_CONT:
case IEEE80211_AMPDU_TX_STOP_FLUSH:
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
ath9k_htc_tx_aggr_oper(priv, vif, sta, action, tid);
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;

View file

@ -344,6 +344,8 @@ void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle,
endpoint->ep_callbacks.tx(endpoint->ep_callbacks.priv,
skb, htc_hdr->endpoint_id,
txok);
} else {
kfree_skb(skb);
}
}

View file

@ -101,22 +101,6 @@ static inline void ath9k_hw_spur_mitigate_freq(struct ath_hw *ah,
ath9k_hw_private_ops(ah)->spur_mitigate_freq(ah, chan);
}
static inline int ath9k_hw_rf_alloc_ext_banks(struct ath_hw *ah)
{
if (!ath9k_hw_private_ops(ah)->rf_alloc_ext_banks)
return 0;
return ath9k_hw_private_ops(ah)->rf_alloc_ext_banks(ah);
}
static inline void ath9k_hw_rf_free_ext_banks(struct ath_hw *ah)
{
if (!ath9k_hw_private_ops(ah)->rf_free_ext_banks)
return;
ath9k_hw_private_ops(ah)->rf_free_ext_banks(ah);
}
static inline bool ath9k_hw_set_rf_regs(struct ath_hw *ah,
struct ath9k_channel *chan,
u16 modesIndex)

View file

@ -54,11 +54,6 @@ static void ath9k_hw_init_cal_settings(struct ath_hw *ah)
ath9k_hw_private_ops(ah)->init_cal_settings(ah);
}
static void ath9k_hw_init_mode_regs(struct ath_hw *ah)
{
ath9k_hw_private_ops(ah)->init_mode_regs(ah);
}
static u32 ath9k_hw_compute_pll_control(struct ath_hw *ah,
struct ath9k_channel *chan)
{
@ -208,7 +203,7 @@ void ath9k_hw_synth_delay(struct ath_hw *ah, struct ath9k_channel *chan,
udelay(hw_delay + BASE_ACTIVATE_DELAY);
}
void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array,
void ath9k_hw_write_array(struct ath_hw *ah, const struct ar5416IniArray *array,
int column, unsigned int *writecnt)
{
int r;
@ -554,28 +549,19 @@ static int ath9k_hw_post_init(struct ath_hw *ah)
ah->eep_ops->get_eeprom_ver(ah),
ah->eep_ops->get_eeprom_rev(ah));
ecode = ath9k_hw_rf_alloc_ext_banks(ah);
if (ecode) {
ath_err(ath9k_hw_common(ah),
"Failed allocating banks for external radio\n");
ath9k_hw_rf_free_ext_banks(ah);
return ecode;
}
if (ah->config.enable_ani) {
ath9k_hw_ani_setup(ah);
if (ah->config.enable_ani)
ath9k_hw_ani_init(ah);
}
return 0;
}
static void ath9k_hw_attach_ops(struct ath_hw *ah)
static int ath9k_hw_attach_ops(struct ath_hw *ah)
{
if (AR_SREV_9300_20_OR_LATER(ah))
ar9003_hw_attach_ops(ah);
else
ar9002_hw_attach_ops(ah);
if (!AR_SREV_9300_20_OR_LATER(ah))
return ar9002_hw_attach_ops(ah);
ar9003_hw_attach_ops(ah);
return 0;
}
/* Called for all hardware families */
@ -611,7 +597,9 @@ static int __ath9k_hw_init(struct ath_hw *ah)
ath9k_hw_init_defaults(ah);
ath9k_hw_init_config(ah);
ath9k_hw_attach_ops(ah);
r = ath9k_hw_attach_ops(ah);
if (r)
return r;
if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) {
ath_err(common, "Couldn't wakeup chip\n");
@ -675,8 +663,6 @@ static int __ath9k_hw_init(struct ath_hw *ah)
if (!AR_SREV_9300_20_OR_LATER(ah))
ah->ani_function &= ~ATH9K_ANI_MRC_CCK;
ath9k_hw_init_mode_regs(ah);
if (!ah->is_pciexpress)
ath9k_hw_disablepcie(ah);
@ -1153,12 +1139,9 @@ void ath9k_hw_deinit(struct ath_hw *ah)
struct ath_common *common = ath9k_hw_common(ah);
if (common->state < ATH_HW_INITIALIZED)
goto free_hw;
return;
ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP);
free_hw:
ath9k_hw_rf_free_ext_banks(ah);
}
EXPORT_SYMBOL(ath9k_hw_deinit);
@ -2576,12 +2559,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
rx_chainmask >>= 1;
}
if (AR_SREV_9300_20_OR_LATER(ah)) {
ah->enabled_cals |= TX_IQ_CAL;
if (AR_SREV_9485_OR_LATER(ah))
ah->enabled_cals |= TX_IQ_ON_AGC_CAL;
}
if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
if (!(ah->ent_mode & AR_ENT_OTP_49GHZ_DISABLE))
pCap->hw_caps |= ATH9K_HW_CAP_MCI;
@ -2590,7 +2567,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
pCap->hw_caps |= ATH9K_HW_CAP_RTT;
}
if (AR_SREV_9280_20_OR_LATER(ah)) {
pCap->hw_caps |= ATH9K_HW_WOW_DEVICE_CAPABLE |
ATH9K_HW_WOW_PATTERN_MATCH_EXACT;

View file

@ -397,6 +397,7 @@ enum ath9k_int {
#define MAX_RTT_TABLE_ENTRY 6
#define MAX_IQCAL_MEASUREMENT 8
#define MAX_CL_TAB_ENTRY 16
#define CL_TAB_ENTRY(reg_base) (reg_base + (4 * j))
struct ath9k_hw_cal_data {
u16 channel;
@ -599,13 +600,10 @@ struct ath_hw_radar_conf {
* @init_cal_settings: setup types of calibrations supported
* @init_cal: starts actual calibration
*
* @init_mode_regs: Initializes mode registers
* @init_mode_gain_regs: Initialize TX/RX gain registers
*
* @rf_set_freq: change frequency
* @spur_mitigate_freq: spur mitigation
* @rf_alloc_ext_banks:
* @rf_free_ext_banks:
* @set_rf_regs:
* @compute_pll_control: compute the PLL control value to use for
* AR_RTC_PLL_CONTROL for a given channel
@ -620,7 +618,6 @@ struct ath_hw_private_ops {
void (*init_cal_settings)(struct ath_hw *ah);
bool (*init_cal)(struct ath_hw *ah, struct ath9k_channel *chan);
void (*init_mode_regs)(struct ath_hw *ah);
void (*init_mode_gain_regs)(struct ath_hw *ah);
void (*setup_calibration)(struct ath_hw *ah,
struct ath9k_cal_list *currCal);
@ -630,8 +627,6 @@ struct ath_hw_private_ops {
struct ath9k_channel *chan);
void (*spur_mitigate_freq)(struct ath_hw *ah,
struct ath9k_channel *chan);
int (*rf_alloc_ext_banks)(struct ath_hw *ah);
void (*rf_free_ext_banks)(struct ath_hw *ah);
bool (*set_rf_regs)(struct ath_hw *ah,
struct ath9k_channel *chan,
u16 modesIndex);
@ -660,6 +655,37 @@ struct ath_hw_private_ops {
void (*ani_cache_ini_regs)(struct ath_hw *ah);
};
/**
* struct ath_spec_scan - parameters for Atheros spectral scan
*
* @enabled: enable/disable spectral scan
* @short_repeat: controls whether the chip is in spectral scan mode
* for 4 usec (enabled) or 204 usec (disabled)
* @count: number of scan results requested. There are special meanings
* in some chip revisions:
* AR92xx: highest bit set (>=128) for endless mode
* (spectral scan won't stopped until explicitly disabled)
* AR9300 and newer: 0 for endless mode
* @endless: true if endless mode is intended. Otherwise, count value is
* corrected to the next possible value.
* @period: time duration between successive spectral scan entry points
* (period*256*Tclk). Tclk = ath_common->clockrate
* @fft_period: PHY passes FFT frames to MAC every (fft_period+1)*4uS
*
* Note: Tclk = 40MHz or 44MHz depending upon operating mode.
* Typically it's 44MHz in 2/5GHz on later chips, but there's
* a "fast clock" check for this in 5GHz.
*
*/
struct ath_spec_scan {
bool enabled;
bool short_repeat;
bool endless;
u8 count;
u8 period;
u8 fft_period;
};
/**
* struct ath_hw_ops - callbacks used by hardware code and driver code
*
@ -668,6 +694,10 @@ struct ath_hw_private_ops {
*
* @config_pci_powersave:
* @calibrate: periodic calibration for NF, ANI, IQ, ADC gain, ADC-DC
*
* @spectral_scan_config: set parameters for spectral scan and enable/disable it
* @spectral_scan_trigger: trigger a spectral scan run
* @spectral_scan_wait: wait for a spectral scan run to finish
*/
struct ath_hw_ops {
void (*config_pci_powersave)(struct ath_hw *ah,
@ -688,6 +718,10 @@ struct ath_hw_ops {
void (*antdiv_comb_conf_set)(struct ath_hw *ah,
struct ath_hw_antcomb_conf *antconf);
void (*antctrl_shared_chain_lnadiv)(struct ath_hw *hw, bool enable);
void (*spectral_scan_config)(struct ath_hw *ah,
struct ath_spec_scan *param);
void (*spectral_scan_trigger)(struct ath_hw *ah);
void (*spectral_scan_wait)(struct ath_hw *ah);
};
struct ath_nf_limits {
@ -710,6 +744,7 @@ enum ath_cal_list {
struct ath_hw {
struct ath_ops reg_ops;
struct device *dev;
struct ieee80211_hw *hw;
struct ath_common common;
struct ath9k_hw_version hw_version;
@ -771,7 +806,6 @@ struct ath_hw {
struct ath9k_cal_list iq_caldata;
struct ath9k_cal_list adcgain_caldata;
struct ath9k_cal_list adcdc_caldata;
struct ath9k_cal_list tempCompCalData;
struct ath9k_cal_list *cal_list;
struct ath9k_cal_list *cal_list_last;
struct ath9k_cal_list *cal_list_curr;
@ -830,10 +864,6 @@ struct ath_hw {
/* ANI */
u32 proc_phyerr;
u32 aniperiod;
int totalSizeDesired[5];
int coarse_high[5];
int coarse_low[5];
int firpwr[5];
enum ath9k_ani_cmd ani_function;
u32 ani_skip_count;
@ -979,7 +1009,7 @@ void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna);
void ath9k_hw_synth_delay(struct ath_hw *ah, struct ath9k_channel *chan,
int hw_delay);
bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout);
void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array,
void ath9k_hw_write_array(struct ath_hw *ah, const struct ar5416IniArray *array,
int column, unsigned int *writecnt);
u32 ath9k_hw_reverse_bits(u32 val, u32 n);
u16 ath9k_hw_computetxtime(struct ath_hw *ah,
@ -1066,16 +1096,17 @@ void ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain);
int ar9003_paprd_init_table(struct ath_hw *ah);
bool ar9003_paprd_is_done(struct ath_hw *ah);
bool ar9003_is_paprd_enabled(struct ath_hw *ah);
void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx);
/* Hardware family op attach helpers */
void ar5008_hw_attach_phy_ops(struct ath_hw *ah);
int ar5008_hw_attach_phy_ops(struct ath_hw *ah);
void ar9002_hw_attach_phy_ops(struct ath_hw *ah);
void ar9003_hw_attach_phy_ops(struct ath_hw *ah);
void ar9002_hw_attach_calib_ops(struct ath_hw *ah);
void ar9003_hw_attach_calib_ops(struct ath_hw *ah);
void ar9002_hw_attach_ops(struct ath_hw *ah);
int ar9002_hw_attach_ops(struct ath_hw *ah);
void ar9003_hw_attach_ops(struct ath_hw *ah);
void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan);

View file

@ -20,6 +20,7 @@
#include <linux/slab.h>
#include <linux/ath9k_platform.h>
#include <linux/module.h>
#include <linux/relay.h>
#include "ath9k.h"
@ -302,16 +303,15 @@ static void setup_ht_cap(struct ath_softc *sc,
ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
}
static int ath9k_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
static void ath9k_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
{
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_ah;
struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
int ret;
ret = ath_reg_notifier_apply(wiphy, request, reg);
ath_reg_notifier_apply(wiphy, request, reg);
/* Set tx power */
if (ah->curchan) {
@ -321,8 +321,6 @@ static int ath9k_reg_notifier(struct wiphy *wiphy,
sc->curtxpow = ath9k_hw_regulatory(ah)->power_limit;
ath9k_ps_restore(sc);
}
return ret;
}
/*
@ -337,7 +335,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
u8 *ds;
struct ath_buf *bf;
int i, bsize, error, desc_len;
int i, bsize, desc_len;
ath_dbg(common, CONFIG, "%s DMA: %u buffers %u desc/buf\n",
name, nbuf, ndesc);
@ -353,8 +351,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
if ((desc_len % 4) != 0) {
ath_err(common, "ath_desc not DWORD aligned\n");
BUG_ON((desc_len % 4) != 0);
error = -ENOMEM;
goto fail;
return -ENOMEM;
}
dd->dd_desc_len = desc_len * nbuf * ndesc;
@ -378,12 +375,11 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
}
/* allocate descriptors */
dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
&dd->dd_desc_paddr, GFP_KERNEL);
if (dd->dd_desc == NULL) {
error = -ENOMEM;
goto fail;
}
dd->dd_desc = dmam_alloc_coherent(sc->dev, dd->dd_desc_len,
&dd->dd_desc_paddr, GFP_KERNEL);
if (!dd->dd_desc)
return -ENOMEM;
ds = (u8 *) dd->dd_desc;
ath_dbg(common, CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n",
name, ds, (u32) dd->dd_desc_len,
@ -391,12 +387,9 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
/* allocate buffers */
bsize = sizeof(struct ath_buf) * nbuf;
bf = kzalloc(bsize, GFP_KERNEL);
if (bf == NULL) {
error = -ENOMEM;
goto fail2;
}
dd->dd_bufptr = bf;
bf = devm_kzalloc(sc->dev, bsize, GFP_KERNEL);
if (!bf)
return -ENOMEM;
for (i = 0; i < nbuf; i++, bf++, ds += (desc_len * ndesc)) {
bf->bf_desc = ds;
@ -422,12 +415,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
list_add_tail(&bf->list, head);
}
return 0;
fail2:
dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
dd->dd_desc_paddr);
fail:
memset(dd, 0, sizeof(*dd));
return error;
}
static int ath9k_init_queues(struct ath_softc *sc)
@ -457,11 +444,13 @@ static int ath9k_init_channels_rates(struct ath_softc *sc)
ATH9K_NUM_CHANNELS);
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) {
channels = kmemdup(ath9k_2ghz_chantable,
channels = devm_kzalloc(sc->dev,
sizeof(ath9k_2ghz_chantable), GFP_KERNEL);
if (!channels)
return -ENOMEM;
memcpy(channels, ath9k_2ghz_chantable,
sizeof(ath9k_2ghz_chantable));
sc->sbands[IEEE80211_BAND_2GHZ].channels = channels;
sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
sc->sbands[IEEE80211_BAND_2GHZ].n_channels =
@ -472,14 +461,13 @@ static int ath9k_init_channels_rates(struct ath_softc *sc)
}
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) {
channels = kmemdup(ath9k_5ghz_chantable,
channels = devm_kzalloc(sc->dev,
sizeof(ath9k_5ghz_chantable), GFP_KERNEL);
if (!channels) {
if (sc->sbands[IEEE80211_BAND_2GHZ].channels)
kfree(sc->sbands[IEEE80211_BAND_2GHZ].channels);
if (!channels)
return -ENOMEM;
}
memcpy(channels, ath9k_5ghz_chantable,
sizeof(ath9k_5ghz_chantable));
sc->sbands[IEEE80211_BAND_5GHZ].channels = channels;
sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
sc->sbands[IEEE80211_BAND_5GHZ].n_channels =
@ -565,10 +553,11 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
int ret = 0, i;
int csz = 0;
ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL);
ah = devm_kzalloc(sc->dev, sizeof(struct ath_hw), GFP_KERNEL);
if (!ah)
return -ENOMEM;
ah->dev = sc->dev;
ah->hw = sc->hw;
ah->hw_version.devid = devid;
ah->reg_ops.read = ath9k_ioread32;
@ -636,7 +625,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
if (pdata && pdata->eeprom_name) {
ret = ath9k_eeprom_request(sc, pdata->eeprom_name);
if (ret)
goto err_eeprom;
return ret;
}
/* Initializes the hardware for all supported chipsets */
@ -676,10 +665,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
ath9k_hw_deinit(ah);
err_hw:
ath9k_eeprom_release(sc);
err_eeprom:
kfree(ah);
sc->sc_ah = NULL;
return ret;
}
@ -844,8 +829,8 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
/* Bring up device */
error = ath9k_init_softc(devid, sc, bus_ops);
if (error != 0)
goto error_init;
if (error)
return error;
ah = sc->sc_ah;
common = ath9k_hw_common(ah);
@ -855,19 +840,19 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
error = ath_regd_init(&common->regulatory, sc->hw->wiphy,
ath9k_reg_notifier);
if (error)
goto error_regd;
goto deinit;
reg = &common->regulatory;
/* Setup TX DMA */
error = ath_tx_init(sc, ATH_TXBUF);
if (error != 0)
goto error_tx;
goto deinit;
/* Setup RX DMA */
error = ath_rx_init(sc, ATH_RXBUF);
if (error != 0)
goto error_rx;
goto deinit;
ath9k_init_txpower_limits(sc);
@ -881,19 +866,19 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
/* Register with mac80211 */
error = ieee80211_register_hw(hw);
if (error)
goto error_register;
goto rx_cleanup;
error = ath9k_init_debug(ah);
if (error) {
ath_err(common, "Unable to create debugfs files\n");
goto error_world;
goto unregister;
}
/* Handle world regulatory */
if (!ath_is_world_regd(reg)) {
error = regulatory_hint(hw->wiphy, reg->alpha2);
if (error)
goto error_world;
goto unregister;
}
ath_init_leds(sc);
@ -901,17 +886,12 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
return 0;
error_world:
unregister:
ieee80211_unregister_hw(hw);
error_register:
rx_cleanup:
ath_rx_cleanup(sc);
error_rx:
ath_tx_cleanup(sc);
error_tx:
/* Nothing */
error_regd:
deinit:
ath9k_deinit_softc(sc);
error_init:
return error;
}
@ -923,12 +903,6 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
{
int i = 0;
if (sc->sbands[IEEE80211_BAND_2GHZ].channels)
kfree(sc->sbands[IEEE80211_BAND_2GHZ].channels);
if (sc->sbands[IEEE80211_BAND_5GHZ].channels)
kfree(sc->sbands[IEEE80211_BAND_5GHZ].channels);
ath9k_deinit_btcoex(sc);
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
@ -940,8 +914,11 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
sc->dfs_detector->exit(sc->dfs_detector);
ath9k_eeprom_release(sc);
kfree(sc->sc_ah);
sc->sc_ah = NULL;
if (sc->rfs_chan_spec_scan) {
relay_close(sc->rfs_chan_spec_scan);
sc->rfs_chan_spec_scan = NULL;
}
}
void ath9k_deinit_device(struct ath_softc *sc)
@ -957,22 +934,9 @@ void ath9k_deinit_device(struct ath_softc *sc)
ieee80211_unregister_hw(hw);
ath_rx_cleanup(sc);
ath_tx_cleanup(sc);
ath9k_deinit_softc(sc);
}
void ath_descdma_cleanup(struct ath_softc *sc,
struct ath_descdma *dd,
struct list_head *head)
{
dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
dd->dd_desc_paddr);
INIT_LIST_HEAD(head);
kfree(dd->dd_bufptr);
memset(dd, 0, sizeof(*dd));
}
/************************/
/* Module Hooks */
/************************/

View file

@ -226,7 +226,8 @@ enum ath9k_phyerr {
ATH9K_PHYERR_HT_LENGTH_ILLEGAL = 35,
ATH9K_PHYERR_HT_RATE_ILLEGAL = 36,
ATH9K_PHYERR_MAX = 37,
ATH9K_PHYERR_SPECTRAL = 38,
ATH9K_PHYERR_MAX = 39,
};
struct ath_desc {

View file

@ -182,7 +182,7 @@ static void ath_restart_work(struct ath_softc *sc)
ath_start_ani(sc);
}
static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush)
static bool ath_prepare_reset(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
bool ret = true;
@ -196,20 +196,12 @@ static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush)
ath9k_debug_samp_bb_mac(sc);
ath9k_hw_disable_interrupts(ah);
if (!ath_drain_all_txq(sc))
ret = false;
if (!ath_stoprecv(sc))
ret = false;
if (!ath_drain_all_txq(sc, retry_tx))
ret = false;
if (!flush) {
if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
ath_rx_tasklet(sc, 1, true);
ath_rx_tasklet(sc, 1, false);
} else {
ath_flushrecv(sc);
}
return ret;
}
@ -255,18 +247,17 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
return true;
}
static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan,
bool retry_tx)
static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_hw_cal_data *caldata = NULL;
bool fastcc = true;
bool flush = false;
int r;
__ath_cancel_work(sc);
tasklet_disable(&sc->intr_tq);
spin_lock_bh(&sc->sc_pcu_lock);
if (!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) {
@ -276,11 +267,10 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan,
if (!hchan) {
fastcc = false;
flush = true;
hchan = ah->curchan;
}
if (!ath_prepare_reset(sc, retry_tx, flush))
if (!ath_prepare_reset(sc))
fastcc = false;
ath_dbg(common, CONFIG, "Reset to %u MHz, HT40: %d fastcc: %d\n",
@ -302,6 +292,8 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan,
out:
spin_unlock_bh(&sc->sc_pcu_lock);
tasklet_enable(&sc->intr_tq);
return r;
}
@ -319,7 +311,7 @@ static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
if (test_bit(SC_OP_INVALID, &sc->sc_flags))
return -EIO;
r = ath_reset_internal(sc, hchan, false);
r = ath_reset_internal(sc, hchan);
return r;
}
@ -549,23 +541,21 @@ irqreturn_t ath_isr(int irq, void *dev)
#undef SCHED_INTR
}
static int ath_reset(struct ath_softc *sc, bool retry_tx)
static int ath_reset(struct ath_softc *sc)
{
int r;
int i, r;
ath9k_ps_wakeup(sc);
r = ath_reset_internal(sc, NULL, retry_tx);
r = ath_reset_internal(sc, NULL);
if (retry_tx) {
int i;
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
if (ATH_TXQ_SETUP(sc, i)) {
spin_lock_bh(&sc->tx.txq[i].axq_lock);
ath_txq_schedule(sc, &sc->tx.txq[i]);
spin_unlock_bh(&sc->tx.txq[i].axq_lock);
}
}
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
if (!ATH_TXQ_SETUP(sc, i))
continue;
spin_lock_bh(&sc->tx.txq[i].axq_lock);
ath_txq_schedule(sc, &sc->tx.txq[i]);
spin_unlock_bh(&sc->tx.txq[i].axq_lock);
}
ath9k_ps_restore(sc);
@ -586,7 +576,7 @@ void ath_reset_work(struct work_struct *work)
{
struct ath_softc *sc = container_of(work, struct ath_softc, hw_reset_work);
ath_reset(sc, true);
ath_reset(sc);
}
/**********************/
@ -804,7 +794,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
}
ath_prepare_reset(sc, false, true);
ath_prepare_reset(sc);
if (sc->rx.frag) {
dev_kfree_skb_any(sc->rx.frag);
@ -1075,6 +1065,86 @@ static void ath9k_disable_ps(struct ath_softc *sc)
ath_dbg(common, PS, "PowerSave disabled\n");
}
void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw)
{
struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
u32 rxfilter;
if (!ath9k_hw_ops(ah)->spectral_scan_trigger) {
ath_err(common, "spectrum analyzer not implemented on this hardware\n");
return;
}
ath9k_ps_wakeup(sc);
rxfilter = ath9k_hw_getrxfilter(ah);
ath9k_hw_setrxfilter(ah, rxfilter |
ATH9K_RX_FILTER_PHYRADAR |
ATH9K_RX_FILTER_PHYERR);
/* TODO: usually this should not be neccesary, but for some reason
* (or in some mode?) the trigger must be called after the
* configuration, otherwise the register will have its values reset
* (on my ar9220 to value 0x01002310)
*/
ath9k_spectral_scan_config(hw, sc->spectral_mode);
ath9k_hw_ops(ah)->spectral_scan_trigger(ah);
ath9k_ps_restore(sc);
}
int ath9k_spectral_scan_config(struct ieee80211_hw *hw,
enum spectral_mode spectral_mode)
{
struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
struct ath_spec_scan param;
if (!ath9k_hw_ops(ah)->spectral_scan_trigger) {
ath_err(common, "spectrum analyzer not implemented on this hardware\n");
return -1;
}
/* NOTE: this will generate a few samples ...
*
* TODO: review default parameters, and/or define an interface to set
* them.
*/
param.enabled = 1;
param.short_repeat = true;
param.count = 8;
param.endless = false;
param.period = 0xFF;
param.fft_period = 0xF;
switch (spectral_mode) {
case SPECTRAL_DISABLED:
param.enabled = 0;
break;
case SPECTRAL_BACKGROUND:
/* send endless samples.
* TODO: is this really useful for "background"?
*/
param.endless = 1;
break;
case SPECTRAL_CHANSCAN:
break;
case SPECTRAL_MANUAL:
break;
default:
return -1;
}
ath9k_ps_wakeup(sc);
ath9k_hw_ops(ah)->spectral_scan_config(ah, &param);
ath9k_ps_restore(sc);
sc->spectral_mode = spectral_mode;
return 0;
}
static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
{
struct ath_softc *sc = hw->priv;
@ -1188,6 +1258,11 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
*/
if (old_pos >= 0)
ath_update_survey_nf(sc, old_pos);
/* perform spectral scan if requested. */
if (sc->scanning && sc->spectral_mode == SPECTRAL_CHANSCAN)
ath9k_spectral_scan_trigger(hw);
}
if (changed & IEEE80211_CONF_CHANGE_POWER) {
@ -1610,7 +1685,9 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
ath9k_ps_restore(sc);
break;
case IEEE80211_AMPDU_TX_STOP:
case IEEE80211_AMPDU_TX_STOP_CONT:
case IEEE80211_AMPDU_TX_STOP_FLUSH:
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
ath9k_ps_wakeup(sc);
ath_tx_aggr_stop(sc, sta, tid);
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
@ -1729,11 +1806,11 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop)
if (drop) {
ath9k_ps_wakeup(sc);
spin_lock_bh(&sc->sc_pcu_lock);
drain_txq = ath_drain_all_txq(sc, false);
drain_txq = ath_drain_all_txq(sc);
spin_unlock_bh(&sc->sc_pcu_lock);
if (!drain_txq)
ath_reset(sc, false);
ath_reset(sc);
ath9k_ps_restore(sc);
ieee80211_wake_queues(hw);
@ -1833,6 +1910,9 @@ static u32 fill_chainmask(u32 cap, u32 new)
static bool validate_antenna_mask(struct ath_hw *ah, u32 val)
{
if (AR_SREV_9300_20_OR_LATER(ah))
return true;
switch (val & 0x7) {
case 0x1:
case 0x3:
@ -2238,6 +2318,19 @@ static void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled)
}
#endif
static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
{
struct ath_softc *sc = hw->priv;
sc->scanning = 1;
}
static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
{
struct ath_softc *sc = hw->priv;
sc->scanning = 0;
}
struct ieee80211_ops ath9k_ops = {
.tx = ath9k_tx,
@ -2284,4 +2377,6 @@ struct ieee80211_ops ath9k_ops = {
.sta_add_debugfs = ath9k_sta_add_debugfs,
.sta_remove_debugfs = ath9k_sta_remove_debugfs,
#endif
.sw_scan_start = ath9k_sw_scan_start,
.sw_scan_complete = ath9k_sw_scan_complete,
};

View file

@ -438,7 +438,7 @@ int ath_mci_setup(struct ath_softc *sc)
struct ath_mci_buf *buf = &mci->sched_buf;
int ret;
buf->bf_addr = dma_alloc_coherent(sc->dev,
buf->bf_addr = dmam_alloc_coherent(sc->dev,
ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE,
&buf->bf_paddr, GFP_KERNEL);
@ -477,11 +477,6 @@ void ath_mci_cleanup(struct ath_softc *sc)
struct ath_mci_coex *mci = &sc->mci_coex;
struct ath_mci_buf *buf = &mci->sched_buf;
if (buf->bf_addr)
dma_free_coherent(sc->dev,
ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE,
buf->bf_addr, buf->bf_paddr);
ar9003_mci_cleanup(ah);
ath_dbg(common, MCI, "MCI De-Initialized\n");

View file

@ -147,7 +147,6 @@ static const struct ath_bus_ops ath_pci_bus_ops = {
static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
void __iomem *mem;
struct ath_softc *sc;
struct ieee80211_hw *hw;
u8 csz;
@ -155,19 +154,19 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
int ret = 0;
char hw_name[64];
if (pci_enable_device(pdev))
if (pcim_enable_device(pdev))
return -EIO;
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (ret) {
pr_err("32-bit DMA not available\n");
goto err_dma;
return ret;
}
ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
if (ret) {
pr_err("32-bit DMA consistent DMA enable failed\n");
goto err_dma;
return ret;
}
/*
@ -203,25 +202,16 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if ((val & 0x0000ff00) != 0)
pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
ret = pci_request_region(pdev, 0, "ath9k");
ret = pcim_iomap_regions(pdev, BIT(0), "ath9k");
if (ret) {
dev_err(&pdev->dev, "PCI memory region reserve error\n");
ret = -ENODEV;
goto err_region;
}
mem = pci_iomap(pdev, 0, 0);
if (!mem) {
pr_err("PCI memory map error\n") ;
ret = -EIO;
goto err_iomap;
return -ENODEV;
}
hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops);
if (!hw) {
dev_err(&pdev->dev, "No memory for ieee80211_hw\n");
ret = -ENOMEM;
goto err_alloc_hw;
return -ENOMEM;
}
SET_IEEE80211_DEV(hw, &pdev->dev);
@ -230,7 +220,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
sc = hw->priv;
sc->hw = hw;
sc->dev = &pdev->dev;
sc->mem = mem;
sc->mem = pcim_iomap_table(pdev)[0];
/* Will be cleared in ath9k_start() */
set_bit(SC_OP_INVALID, &sc->sc_flags);
@ -251,7 +241,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ath9k_hw_name(sc->sc_ah, hw_name, sizeof(hw_name));
wiphy_info(hw->wiphy, "%s mem=0x%lx, irq=%d\n",
hw_name, (unsigned long)mem, pdev->irq);
hw_name, (unsigned long)sc->mem, pdev->irq);
return 0;
@ -259,14 +249,6 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
free_irq(sc->irq, sc);
err_irq:
ieee80211_free_hw(hw);
err_alloc_hw:
pci_iounmap(pdev, mem);
err_iomap:
pci_release_region(pdev, 0);
err_region:
/* Nothing */
err_dma:
pci_disable_device(pdev);
return ret;
}
@ -274,17 +256,12 @@ static void ath_pci_remove(struct pci_dev *pdev)
{
struct ieee80211_hw *hw = pci_get_drvdata(pdev);
struct ath_softc *sc = hw->priv;
void __iomem *mem = sc->mem;
if (!is_ath9k_unloaded)
sc->sc_ah->ah_flags |= AH_UNPLUGGED;
ath9k_deinit_device(sc);
free_irq(sc->irq, sc);
ieee80211_free_hw(sc->hw);
pci_iounmap(pdev, mem);
pci_disable_device(pdev);
pci_release_region(pdev, 0);
}
#ifdef CONFIG_PM_SLEEP

View file

@ -15,6 +15,7 @@
*/
#include <linux/dma-mapping.h>
#include <linux/relay.h>
#include "ath9k.h"
#include "ar9003_mac.h"
@ -180,11 +181,6 @@ static void ath_rx_edma_cleanup(struct ath_softc *sc)
bf->bf_mpdu = NULL;
}
}
INIT_LIST_HEAD(&sc->rx.rxbuf);
kfree(sc->rx.rx_bufptr);
sc->rx.rx_bufptr = NULL;
}
static void ath_rx_edma_init_queue(struct ath_rx_edma *rx_edma, int size)
@ -211,12 +207,11 @@ static int ath_rx_edma_init(struct ath_softc *sc, int nbufs)
ah->caps.rx_hp_qdepth);
size = sizeof(struct ath_buf) * nbufs;
bf = kzalloc(size, GFP_KERNEL);
bf = devm_kzalloc(sc->dev, size, GFP_KERNEL);
if (!bf)
return -ENOMEM;
INIT_LIST_HEAD(&sc->rx.rxbuf);
sc->rx.rx_bufptr = bf;
for (i = 0; i < nbufs; i++, bf++) {
skb = ath_rxbuf_alloc(common, common->rx_bufsize, GFP_KERNEL);
@ -254,8 +249,6 @@ static int ath_rx_edma_init(struct ath_softc *sc, int nbufs)
static void ath_edma_start_recv(struct ath_softc *sc)
{
spin_lock_bh(&sc->rx.rxbuflock);
ath9k_hw_rxena(sc->sc_ah);
ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_HP,
@ -267,8 +260,6 @@ static void ath_edma_start_recv(struct ath_softc *sc)
ath_opmode_init(sc);
ath9k_hw_startpcureceive(sc->sc_ah, !!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL));
spin_unlock_bh(&sc->rx.rxbuflock);
}
static void ath_edma_stop_recv(struct ath_softc *sc)
@ -285,8 +276,6 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
int error = 0;
spin_lock_init(&sc->sc_pcu_lock);
spin_lock_init(&sc->rx.rxbuflock);
clear_bit(SC_OP_RXFLUSH, &sc->sc_flags);
common->rx_bufsize = IEEE80211_MAX_MPDU_LEN / 2 +
sc->sc_ah->caps.rx_status_len;
@ -363,9 +352,6 @@ void ath_rx_cleanup(struct ath_softc *sc)
bf->bf_mpdu = NULL;
}
}
if (sc->rx.rxdma.dd_desc_len != 0)
ath_descdma_cleanup(sc, &sc->rx.rxdma, &sc->rx.rxbuf);
}
}
@ -447,7 +433,6 @@ int ath_startrecv(struct ath_softc *sc)
return 0;
}
spin_lock_bh(&sc->rx.rxbuflock);
if (list_empty(&sc->rx.rxbuf))
goto start_recv;
@ -468,26 +453,31 @@ int ath_startrecv(struct ath_softc *sc)
ath_opmode_init(sc);
ath9k_hw_startpcureceive(ah, !!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL));
spin_unlock_bh(&sc->rx.rxbuflock);
return 0;
}
static void ath_flushrecv(struct ath_softc *sc)
{
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
ath_rx_tasklet(sc, 1, true);
ath_rx_tasklet(sc, 1, false);
}
bool ath_stoprecv(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
bool stopped, reset = false;
spin_lock_bh(&sc->rx.rxbuflock);
ath9k_hw_abortpcurecv(ah);
ath9k_hw_setrxfilter(ah, 0);
stopped = ath9k_hw_stopdmarecv(ah, &reset);
ath_flushrecv(sc);
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
ath_edma_stop_recv(sc);
else
sc->rx.rxlink = NULL;
spin_unlock_bh(&sc->rx.rxbuflock);
if (!(ah->ah_flags & AH_UNPLUGGED) &&
unlikely(!stopped)) {
@ -499,15 +489,6 @@ bool ath_stoprecv(struct ath_softc *sc)
return stopped && !reset;
}
void ath_flushrecv(struct ath_softc *sc)
{
set_bit(SC_OP_RXFLUSH, &sc->sc_flags);
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
ath_rx_tasklet(sc, 1, true);
ath_rx_tasklet(sc, 1, false);
clear_bit(SC_OP_RXFLUSH, &sc->sc_flags);
}
static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb)
{
/* Check whether the Beacon frame has DTIM indicating buffered bc/mc */
@ -744,6 +725,7 @@ static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc,
return NULL;
}
list_del(&bf->list);
if (!bf->bf_mpdu)
return bf;
@ -1034,6 +1016,108 @@ static void ath9k_rx_skb_postprocess(struct ath_common *common,
rxs->flag &= ~RX_FLAG_DECRYPTED;
}
static s8 fix_rssi_inv_only(u8 rssi_val)
{
if (rssi_val == 128)
rssi_val = 0;
return (s8) rssi_val;
}
static void ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr,
struct ath_rx_status *rs, u64 tsf)
{
#ifdef CONFIG_ATH_DEBUG
struct ath_hw *ah = sc->sc_ah;
u8 bins[SPECTRAL_HT20_NUM_BINS];
u8 *vdata = (u8 *)hdr;
struct fft_sample_ht20 fft_sample;
struct ath_radar_info *radar_info;
struct ath_ht20_mag_info *mag_info;
int len = rs->rs_datalen;
int i, dc_pos;
/* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer
* via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT
* yet, but this is supposed to be possible as well.
*/
if (rs->rs_phyerr != ATH9K_PHYERR_RADAR &&
rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT &&
rs->rs_phyerr != ATH9K_PHYERR_SPECTRAL)
return;
/* Variation in the data length is possible and will be fixed later.
* Note that we only support HT20 for now.
*
* TODO: add HT20_40 support as well.
*/
if ((len > SPECTRAL_HT20_TOTAL_DATA_LEN + 2) ||
(len < SPECTRAL_HT20_TOTAL_DATA_LEN - 1))
return;
/* check if spectral scan bit is set. This does not have to be checked
* if received through a SPECTRAL phy error, but shouldn't hurt.
*/
radar_info = ((struct ath_radar_info *)&vdata[len]) - 1;
if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK))
return;
fft_sample.tlv.type = ATH_FFT_SAMPLE_HT20;
fft_sample.tlv.length = sizeof(fft_sample) - sizeof(fft_sample.tlv);
fft_sample.freq = ah->curchan->chan->center_freq;
fft_sample.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0);
fft_sample.noise = ah->noise;
switch (len - SPECTRAL_HT20_TOTAL_DATA_LEN) {
case 0:
/* length correct, nothing to do. */
memcpy(bins, vdata, SPECTRAL_HT20_NUM_BINS);
break;
case -1:
/* first byte missing, duplicate it. */
memcpy(&bins[1], vdata, SPECTRAL_HT20_NUM_BINS - 1);
bins[0] = vdata[0];
break;
case 2:
/* MAC added 2 extra bytes at bin 30 and 32, remove them. */
memcpy(bins, vdata, 30);
bins[30] = vdata[31];
memcpy(&bins[31], &vdata[33], SPECTRAL_HT20_NUM_BINS - 31);
break;
case 1:
/* MAC added 2 extra bytes AND first byte is missing. */
bins[0] = vdata[0];
memcpy(&bins[0], vdata, 30);
bins[31] = vdata[31];
memcpy(&bins[32], &vdata[33], SPECTRAL_HT20_NUM_BINS - 32);
break;
default:
return;
}
/* DC value (value in the middle) is the blind spot of the spectral
* sample and invalid, interpolate it.
*/
dc_pos = SPECTRAL_HT20_NUM_BINS / 2;
bins[dc_pos] = (bins[dc_pos + 1] + bins[dc_pos - 1]) / 2;
/* mag data is at the end of the frame, in front of radar_info */
mag_info = ((struct ath_ht20_mag_info *)radar_info) - 1;
/* Apply exponent and grab further auxiliary information. */
for (i = 0; i < SPECTRAL_HT20_NUM_BINS; i++)
fft_sample.data[i] = bins[i] << mag_info->max_exp;
fft_sample.max_magnitude = spectral_max_magnitude(mag_info->all_bins);
fft_sample.max_index = spectral_max_index(mag_info->all_bins);
fft_sample.bitmap_weight = spectral_bitmap_weight(mag_info->all_bins);
fft_sample.tsf = tsf;
ath_debug_send_fft_sample(sc, &fft_sample.tlv);
#endif
}
int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
{
struct ath_buf *bf;
@ -1059,16 +1143,12 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
dma_type = DMA_FROM_DEVICE;
qtype = hp ? ATH9K_RX_QUEUE_HP : ATH9K_RX_QUEUE_LP;
spin_lock_bh(&sc->rx.rxbuflock);
tsf = ath9k_hw_gettsf64(ah);
tsf_lower = tsf & 0xffffffff;
do {
bool decrypt_error = false;
/* If handling rx interrupt and flush is in progress => exit */
if (test_bit(SC_OP_RXFLUSH, &sc->sc_flags) && (flush == 0))
break;
memset(&rs, 0, sizeof(rs));
if (edma)
@ -1111,15 +1191,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
ath_debug_stat_rx(sc, &rs);
/*
* If we're asked to flush receive queue, directly
* chain it back at the queue without processing it.
*/
if (test_bit(SC_OP_RXFLUSH, &sc->sc_flags)) {
RX_STAT_INC(rx_drop_rxflush);
goto requeue_drop_frag;
}
memset(rxs, 0, sizeof(struct ieee80211_rx_status));
rxs->mactime = (tsf & ~0xffffffffULL) | rs.rs_tstamp;
@ -1131,6 +1202,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
unlikely(tsf_lower - rs.rs_tstamp > 0x10000000))
rxs->mactime += 0x100000000ULL;
if ((rs.rs_status & ATH9K_RXERR_PHY))
ath_process_fft(sc, hdr, &rs, rxs->mactime);
retval = ath9k_rx_skb_preprocess(common, hw, hdr, &rs,
rxs, &decrypt_error);
if (retval)
@ -1254,19 +1328,18 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
sc->rx.frag = NULL;
}
requeue:
list_add_tail(&bf->list, &sc->rx.rxbuf);
if (flush)
continue;
if (edma) {
list_add_tail(&bf->list, &sc->rx.rxbuf);
ath_rx_edma_buf_link(sc, qtype);
} else {
list_move_tail(&bf->list, &sc->rx.rxbuf);
ath_rx_buf_link(sc, bf);
if (!flush)
ath9k_hw_rxena(ah);
ath9k_hw_rxena(ah);
}
} while (1);
spin_unlock_bh(&sc->rx.rxbuflock);
if (!(ah->imask & ATH9K_INT_RXEOL)) {
ah->imask |= (ATH9K_INT_RXEOL | ATH9K_INT_RXORN);
ath9k_hw_set_interrupts(ah);

View file

@ -789,6 +789,7 @@
#define AR_SREV_REVISION_9271_11 1
#define AR_SREV_VERSION_9300 0x1c0
#define AR_SREV_REVISION_9300_20 2 /* 2.0 and 2.1 */
#define AR_SREV_REVISION_9300_22 3
#define AR_SREV_VERSION_9330 0x200
#define AR_SREV_REVISION_9330_10 0
#define AR_SREV_REVISION_9330_11 1
@ -869,6 +870,9 @@
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300))
#define AR_SREV_9300_20_OR_LATER(_ah) \
((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9300)
#define AR_SREV_9300_22(_ah) \
(AR_SREV_9300(ah) && \
((_ah)->hw_version.macRev == AR_SREV_REVISION_9300_22))
#define AR_SREV_9330(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9330))
@ -884,9 +888,6 @@
#define AR_SREV_9485(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485))
#define AR_SREV_9485_10(_ah) \
(AR_SREV_9485(_ah) && \
((_ah)->hw_version.macRev == AR_SREV_REVISION_9485_10))
#define AR_SREV_9485_11(_ah) \
(AR_SREV_9485(_ah) && \
((_ah)->hw_version.macRev == AR_SREV_REVISION_9485_11))

View file

@ -378,7 +378,7 @@ static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf,
static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
struct ath_buf *bf, struct list_head *bf_q,
struct ath_tx_status *ts, int txok, bool retry)
struct ath_tx_status *ts, int txok)
{
struct ath_node *an = NULL;
struct sk_buff *skb;
@ -490,7 +490,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
} else if (!isaggr && txok) {
/* transmit completion */
acked_cnt++;
} else if ((tid->state & AGGR_CLEANUP) || !retry) {
} else if (tid->state & AGGR_CLEANUP) {
/*
* cleanup in progress, just fail
* the un-acked sub-frames
@ -604,6 +604,37 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
ath9k_queue_reset(sc, RESET_TYPE_TX_ERROR);
}
static bool bf_is_ampdu_not_probing(struct ath_buf *bf)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(bf->bf_mpdu);
return bf_isampdu(bf) && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
}
static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
struct ath_tx_status *ts, struct ath_buf *bf,
struct list_head *bf_head)
{
bool txok, flush;
txok = !(ts->ts_status & ATH9K_TXERR_MASK);
flush = !!(ts->ts_status & ATH9K_TX_FLUSH);
txq->axq_tx_inprogress = false;
txq->axq_depth--;
if (bf_is_ampdu_not_probing(bf))
txq->axq_ampdu_depth--;
if (!bf_isampdu(bf)) {
if (!flush)
ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok);
ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok);
} else
ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok);
if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) && !flush)
ath_txq_schedule(sc, txq);
}
static bool ath_lookup_legacy(struct ath_buf *bf)
{
struct sk_buff *skb;
@ -1331,23 +1362,6 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid
/* Queue Management */
/********************/
static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
struct ath_txq *txq)
{
struct ath_atx_ac *ac, *ac_tmp;
struct ath_atx_tid *tid, *tid_tmp;
list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) {
list_del(&ac->list);
ac->sched = false;
list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) {
list_del(&tid->list);
tid->sched = false;
ath_tid_drain(sc, txq, tid);
}
}
}
struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
{
struct ath_hw *ah = sc->sc_ah;
@ -1470,14 +1484,8 @@ int ath_cabq_update(struct ath_softc *sc)
return 0;
}
static bool bf_is_ampdu_not_probing(struct ath_buf *bf)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(bf->bf_mpdu);
return bf_isampdu(bf) && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
}
static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq,
struct list_head *list, bool retry_tx)
struct list_head *list)
{
struct ath_buf *bf, *lastbf;
struct list_head bf_head;
@ -1499,16 +1507,7 @@ static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq,
lastbf = bf->bf_lastbf;
list_cut_position(&bf_head, list, &lastbf->list);
txq->axq_depth--;
if (bf_is_ampdu_not_probing(bf))
txq->axq_ampdu_depth--;
if (bf_isampdu(bf))
ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0,
retry_tx);
else
ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head);
}
}
@ -1518,7 +1517,7 @@ static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq,
* This assumes output has been stopped and
* we do not need to block ath_tx_tasklet.
*/
void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq)
{
ath_txq_lock(sc, txq);
@ -1526,8 +1525,7 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
int idx = txq->txq_tailidx;
while (!list_empty(&txq->txq_fifo[idx])) {
ath_drain_txq_list(sc, txq, &txq->txq_fifo[idx],
retry_tx);
ath_drain_txq_list(sc, txq, &txq->txq_fifo[idx]);
INCR(idx, ATH_TXFIFO_DEPTH);
}
@ -1536,16 +1534,12 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
txq->axq_link = NULL;
txq->axq_tx_inprogress = false;
ath_drain_txq_list(sc, txq, &txq->axq_q, retry_tx);
/* flush any pending frames if aggregation is enabled */
if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) && !retry_tx)
ath_txq_drain_pending_buffers(sc, txq);
ath_drain_txq_list(sc, txq, &txq->axq_q);
ath_txq_unlock_complete(sc, txq);
}
bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
bool ath_drain_all_txq(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
@ -1581,7 +1575,7 @@ bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
*/
txq = &sc->tx.txq[i];
txq->stopped = false;
ath_draintxq(sc, txq, retry_tx);
ath_draintxq(sc, txq);
}
return !npend;
@ -2175,28 +2169,6 @@ static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf,
tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
}
static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
struct ath_tx_status *ts, struct ath_buf *bf,
struct list_head *bf_head)
{
int txok;
txq->axq_depth--;
txok = !(ts->ts_status & ATH9K_TXERR_MASK);
txq->axq_tx_inprogress = false;
if (bf_is_ampdu_not_probing(bf))
txq->axq_ampdu_depth--;
if (!bf_isampdu(bf)) {
ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok);
ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok);
} else
ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok, true);
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)
ath_txq_schedule(sc, txq);
}
static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
{
struct ath_hw *ah = sc->sc_ah;
@ -2361,8 +2333,8 @@ static int ath_txstatus_setup(struct ath_softc *sc, int size)
u8 txs_len = sc->sc_ah->caps.txs_len;
dd->dd_desc_len = size * txs_len;
dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
&dd->dd_desc_paddr, GFP_KERNEL);
dd->dd_desc = dmam_alloc_coherent(sc->dev, dd->dd_desc_len,
&dd->dd_desc_paddr, GFP_KERNEL);
if (!dd->dd_desc)
return -ENOMEM;
@ -2382,14 +2354,6 @@ static int ath_tx_edma_init(struct ath_softc *sc)
return err;
}
static void ath_tx_edma_cleanup(struct ath_softc *sc)
{
struct ath_descdma *dd = &sc->txsdma;
dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
dd->dd_desc_paddr);
}
int ath_tx_init(struct ath_softc *sc, int nbufs)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
@ -2402,7 +2366,7 @@ int ath_tx_init(struct ath_softc *sc, int nbufs)
if (error != 0) {
ath_err(common,
"Failed to allocate tx descriptors: %d\n", error);
goto err;
return error;
}
error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
@ -2410,36 +2374,17 @@ int ath_tx_init(struct ath_softc *sc, int nbufs)
if (error != 0) {
ath_err(common,
"Failed to allocate beacon descriptors: %d\n", error);
goto err;
return error;
}
INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
error = ath_tx_edma_init(sc);
if (error)
goto err;
}
err:
if (error != 0)
ath_tx_cleanup(sc);
return error;
}
void ath_tx_cleanup(struct ath_softc *sc)
{
if (sc->beacon.bdma.dd_desc_len != 0)
ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf);
if (sc->tx.txdma.dd_desc_len != 0)
ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf);
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
ath_tx_edma_cleanup(sc);
}
void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
{
struct ath_atx_tid *tid;

View file

@ -85,20 +85,14 @@ enum carl9170_device_state {
CARL9170_STARTED,
};
#define CARL9170_NUM_TID 16
#define WME_BA_BMP_SIZE 64
#define CARL9170_TX_USER_RATE_TRIES 3
#define WME_AC_BE 2
#define WME_AC_BK 3
#define WME_AC_VI 1
#define WME_AC_VO 0
#define TID_TO_WME_AC(_tid) \
((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \
(((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \
(((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \
WME_AC_VO)
((((_tid) == 0) || ((_tid) == 3)) ? IEEE80211_AC_BE : \
(((_tid) == 1) || ((_tid) == 2)) ? IEEE80211_AC_BK : \
(((_tid) == 4) || ((_tid) == 5)) ? IEEE80211_AC_VI : \
IEEE80211_AC_VO)
#define SEQ_DIFF(_start, _seq) \
(((_start) - (_seq)) & 0x0fff)
@ -290,6 +284,7 @@ struct ar9170 {
unsigned int rx_size;
unsigned int tx_seq_table;
bool ba_filter;
bool disable_offload_fw;
} fw;
/* interface configuration combinations */
@ -493,8 +488,8 @@ struct carl9170_sta_info {
bool sleeping;
atomic_t pending_frames;
unsigned int ampdu_max_len;
struct carl9170_sta_tid __rcu *agg[CARL9170_NUM_TID];
struct carl9170_ba_stats stats[CARL9170_NUM_TID];
struct carl9170_sta_tid __rcu *agg[IEEE80211_NUM_TIDS];
struct carl9170_ba_stats stats[IEEE80211_NUM_TIDS];
};
struct carl9170_tx_info {

View file

@ -215,6 +215,24 @@ static int carl9170_fw_tx_sequence(struct ar9170 *ar)
return 0;
}
static void carl9170_fw_set_if_combinations(struct ar9170 *ar,
u16 if_comb_types)
{
if (ar->fw.vif_num < 2)
return;
ar->if_comb_limits[0].max = ar->fw.vif_num;
ar->if_comb_limits[0].types = if_comb_types;
ar->if_combs[0].num_different_channels = 1;
ar->if_combs[0].max_interfaces = ar->fw.vif_num;
ar->if_combs[0].limits = ar->if_comb_limits;
ar->if_combs[0].n_limits = ARRAY_SIZE(ar->if_comb_limits);
ar->hw->wiphy->iface_combinations = ar->if_combs;
ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ar->if_combs);
}
static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
{
const struct carl9170fw_otus_desc *otus_desc;
@ -264,7 +282,7 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
if (!SUPP(CARL9170FW_COMMAND_CAM)) {
dev_info(&ar->udev->dev, "crypto offloading is disabled "
"by firmware.\n");
ar->disable_offload = true;
ar->fw.disable_offload_fw = true;
}
if (SUPP(CARL9170FW_PSM) && SUPP(CARL9170FW_FIXED_5GHZ_PSM))
@ -345,20 +363,15 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
}
}
ar->if_comb_limits[0].max = ar->fw.vif_num;
ar->if_comb_limits[0].types = if_comb_types;
ar->if_combs[0].num_different_channels = 1;
ar->if_combs[0].max_interfaces = ar->fw.vif_num;
ar->if_combs[0].limits = ar->if_comb_limits;
ar->if_combs[0].n_limits = ARRAY_SIZE(ar->if_comb_limits);
ar->hw->wiphy->iface_combinations = ar->if_combs;
ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ar->if_combs);
carl9170_fw_set_if_combinations(ar, if_comb_types);
ar->hw->wiphy->interface_modes |= if_comb_types;
ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
ar->hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
/* As IBSS Encryption is software-based, IBSS RSN is supported. */
ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
WIPHY_FLAG_IBSS_RSN | WIPHY_FLAG_SUPPORTS_TDLS;
#undef SUPPORTED
return carl9170_fw_tx_sequence(ar);

View file

@ -156,6 +156,14 @@ struct carl9170_psm {
} __packed;
#define CARL9170_PSM_SIZE 4
/*
* Note: If a bit in rx_filter is set, then it
* means that the particular frames which matches
* the condition are FILTERED/REMOVED/DISCARDED!
* (This is can be a bit confusing, especially
* because someone people think it's the exact
* opposite way, so watch out!)
*/
struct carl9170_rx_filter_cmd {
__le32 rx_filter;
} __packed;

View file

@ -384,7 +384,7 @@
#define AR9170_MAC_REG_BCN_ADDR (AR9170_MAC_REG_BASE + 0xd84)
#define AR9170_MAC_REG_BCN_LENGTH (AR9170_MAC_REG_BASE + 0xd88)
#define AR9170_MAC_BCN_LENGTH_MAX 256
#define AR9170_MAC_BCN_LENGTH_MAX (512 - 32)
#define AR9170_MAC_REG_BCN_STATUS (AR9170_MAC_REG_BASE + 0xd8c)

View file

@ -358,8 +358,13 @@ static int carl9170_op_start(struct ieee80211_hw *hw)
ar->ps.last_action = jiffies;
ar->ps.last_slept = jiffies;
ar->erp_mode = CARL9170_ERP_AUTO;
ar->rx_software_decryption = false;
ar->disable_offload = false;
/* Set "disable hw crypto offload" whenever the module parameter
* nohwcrypt is true or if the firmware does not support it.
*/
ar->disable_offload = modparam_nohwcrypt |
ar->fw.disable_offload_fw;
ar->rx_software_decryption = ar->disable_offload;
for (i = 0; i < ar->hw->queues; i++) {
ar->queue_stop_timeout[i] = jiffies;
@ -565,12 +570,28 @@ static int carl9170_init_interface(struct ar9170 *ar,
memcpy(common->macaddr, vif->addr, ETH_ALEN);
if (modparam_nohwcrypt ||
((vif->type != NL80211_IFTYPE_STATION) &&
(vif->type != NL80211_IFTYPE_AP))) {
ar->rx_software_decryption = true;
ar->disable_offload = true;
}
/* We have to fall back to software crypto, whenever
* the user choose to participates in an IBSS. HW
* offload for IBSS RSN is not supported by this driver.
*
* NOTE: If the previous main interface has already
* disabled hw crypto offload, we have to keep this
* previous disable_offload setting as it was.
* Altough ideally, we should notify mac80211 and tell
* it to forget about any HW crypto offload for now.
*/
ar->disable_offload |= ((vif->type != NL80211_IFTYPE_STATION) &&
(vif->type != NL80211_IFTYPE_AP));
/* While the driver supports HW offload in a single
* P2P client configuration, it doesn't support HW
* offload in the favourit, concurrent P2P GO+CLIENT
* configuration. Hence, HW offload will always be
* disabled for P2P.
*/
ar->disable_offload |= vif->p2p;
ar->rx_software_decryption = ar->disable_offload;
err = carl9170_set_operating_mode(ar);
return err;
@ -580,7 +601,7 @@ static int carl9170_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct carl9170_vif_info *vif_priv = (void *) vif->drv_priv;
struct ieee80211_vif *main_vif;
struct ieee80211_vif *main_vif, *old_main = NULL;
struct ar9170 *ar = hw->priv;
int vif_id = -1, err = 0;
@ -602,6 +623,15 @@ static int carl9170_op_add_interface(struct ieee80211_hw *hw,
goto init;
}
/* Because the AR9170 HW's MAC doesn't provide full support for
* multiple, independent interfaces [of different operation modes].
* We have to select ONE main interface [main mode of HW], but we
* can have multiple slaves [AKA: entry in the ACK-table].
*
* The first (from HEAD/TOP) interface in the ar->vif_list is
* always the main intf. All following intfs in this list
* are considered to be slave intfs.
*/
main_vif = carl9170_get_main_vif(ar);
if (main_vif) {
@ -610,6 +640,18 @@ static int carl9170_op_add_interface(struct ieee80211_hw *hw,
if (vif->type == NL80211_IFTYPE_STATION)
break;
/* P2P GO [master] use-case
* Because the P2P GO station is selected dynamically
* by all participating peers of a WIFI Direct network,
* the driver has be able to change the main interface
* operating mode on the fly.
*/
if (main_vif->p2p && vif->p2p &&
vif->type == NL80211_IFTYPE_AP) {
old_main = main_vif;
break;
}
err = -EBUSY;
rcu_read_unlock();
@ -648,14 +690,41 @@ static int carl9170_op_add_interface(struct ieee80211_hw *hw,
vif_priv->id = vif_id;
vif_priv->enable_beacon = false;
ar->vifs++;
list_add_tail_rcu(&vif_priv->list, &ar->vif_list);
if (old_main) {
/* We end up in here, if the main interface is being replaced.
* Put the new main interface at the HEAD of the list and the
* previous inteface will automatically become second in line.
*/
list_add_rcu(&vif_priv->list, &ar->vif_list);
} else {
/* Add new inteface. If the list is empty, it will become the
* main inteface, otherwise it will be slave.
*/
list_add_tail_rcu(&vif_priv->list, &ar->vif_list);
}
rcu_assign_pointer(ar->vif_priv[vif_id].vif, vif);
init:
if (carl9170_get_main_vif(ar) == vif) {
main_vif = carl9170_get_main_vif(ar);
if (main_vif == vif) {
rcu_assign_pointer(ar->beacon_iter, vif_priv);
rcu_read_unlock();
if (old_main) {
struct carl9170_vif_info *old_main_priv =
(void *) old_main->drv_priv;
/* downgrade old main intf to slave intf.
* NOTE: We are no longer under rcu_read_lock.
* But we are still holding ar->mutex, so the
* vif data [id, addr] is safe.
*/
err = carl9170_mod_virtual_mac(ar, old_main_priv->id,
old_main->addr);
if (err)
goto unlock;
}
err = carl9170_init_interface(ar, vif);
if (err)
goto unlock;
@ -1112,9 +1181,7 @@ static int carl9170_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
if (ar->disable_offload || !vif)
return -EOPNOTSUPP;
/*
* We have to fall back to software encryption, whenever
* the user choose to participates in an IBSS or is connected
/* Fall back to software encryption whenever the driver is connected
* to more than one network.
*
* This is very unfortunate, because some machines cannot handle
@ -1263,7 +1330,7 @@ static int carl9170_op_sta_add(struct ieee80211_hw *hw,
return 0;
}
for (i = 0; i < CARL9170_NUM_TID; i++)
for (i = 0; i < ARRAY_SIZE(sta_info->agg); i++)
RCU_INIT_POINTER(sta_info->agg[i], NULL);
sta_info->ampdu_max_len = 1 << (3 + sta->ht_cap.ampdu_factor);
@ -1287,7 +1354,7 @@ static int carl9170_op_sta_remove(struct ieee80211_hw *hw,
sta_info->ht_sta = false;
rcu_read_lock();
for (i = 0; i < CARL9170_NUM_TID; i++) {
for (i = 0; i < ARRAY_SIZE(sta_info->agg); i++) {
struct carl9170_sta_tid *tid_info;
tid_info = rcu_dereference(sta_info->agg[i]);
@ -1394,7 +1461,9 @@ static int carl9170_op_ampdu_action(struct ieee80211_hw *hw,
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
case IEEE80211_AMPDU_TX_STOP:
case IEEE80211_AMPDU_TX_STOP_CONT:
case IEEE80211_AMPDU_TX_STOP_FLUSH:
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
rcu_read_lock();
tid_info = rcu_dereference(sta_info->agg[tid]);
if (tid_info) {
@ -1805,10 +1874,6 @@ void *carl9170_alloc(size_t priv_size)
for (i = 0; i < ARRAY_SIZE(ar->noise); i++)
ar->noise[i] = -95; /* ATH_DEFAULT_NOISE_FLOOR */
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
/* As IBSS Encryption is software-based, IBSS RSN is supported. */
hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
return ar;
err_nomem:
@ -1916,13 +1981,13 @@ static int carl9170_parse_eeprom(struct ar9170 *ar)
return 0;
}
static int carl9170_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
static void carl9170_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
{
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct ar9170 *ar = hw->priv;
return ath_reg_notifier_apply(wiphy, request, &ar->common.regulatory);
ath_reg_notifier_apply(wiphy, request, &ar->common.regulatory);
}
int carl9170_register(struct ar9170 *ar)

View file

@ -1520,36 +1520,93 @@ void carl9170_tx_scheduler(struct ar9170 *ar)
carl9170_tx(ar);
}
/* caller has to take rcu_read_lock */
static struct carl9170_vif_info *carl9170_pick_beaconing_vif(struct ar9170 *ar)
{
struct carl9170_vif_info *cvif;
int i = 1;
/* The AR9170 hardware has no fancy beacon queue or some
* other scheduling mechanism. So, the driver has to make
* due by setting the two beacon timers (pretbtt and tbtt)
* once and then swapping the beacon address in the HW's
* register file each time the pretbtt fires.
*/
cvif = rcu_dereference(ar->beacon_iter);
if (ar->vifs > 0 && cvif) {
do {
list_for_each_entry_continue_rcu(cvif, &ar->vif_list,
list) {
if (cvif->active && cvif->enable_beacon)
goto out;
}
} while (ar->beacon_enabled && i--);
}
out:
rcu_assign_pointer(ar->beacon_iter, cvif);
return cvif;
}
static bool carl9170_tx_beacon_physet(struct ar9170 *ar, struct sk_buff *skb,
u32 *ht1, u32 *plcp)
{
struct ieee80211_tx_info *txinfo;
struct ieee80211_tx_rate *rate;
unsigned int power, chains;
bool ht_rate;
txinfo = IEEE80211_SKB_CB(skb);
rate = &txinfo->control.rates[0];
ht_rate = !!(txinfo->control.rates[0].flags & IEEE80211_TX_RC_MCS);
carl9170_tx_rate_tpc_chains(ar, txinfo, rate, plcp, &power, &chains);
*ht1 = AR9170_MAC_BCN_HT1_TX_ANT0;
if (chains == AR9170_TX_PHY_TXCHAIN_2)
*ht1 |= AR9170_MAC_BCN_HT1_TX_ANT1;
SET_VAL(AR9170_MAC_BCN_HT1_PWR_CTRL, *ht1, 7);
SET_VAL(AR9170_MAC_BCN_HT1_TPC, *ht1, power);
SET_VAL(AR9170_MAC_BCN_HT1_CHAIN_MASK, *ht1, chains);
if (ht_rate) {
*ht1 |= AR9170_MAC_BCN_HT1_HT_EN;
if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
*plcp |= AR9170_MAC_BCN_HT2_SGI;
if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) {
*ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_SHARED;
*plcp |= AR9170_MAC_BCN_HT2_BW40;
} else if (rate->flags & IEEE80211_TX_RC_DUP_DATA) {
*ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_DUP;
*plcp |= AR9170_MAC_BCN_HT2_BW40;
}
SET_VAL(AR9170_MAC_BCN_HT2_LEN, *plcp, skb->len + FCS_LEN);
} else {
if (*plcp <= AR9170_TX_PHY_RATE_CCK_11M)
*plcp |= ((skb->len + FCS_LEN) << (3 + 16)) + 0x0400;
else
*plcp |= ((skb->len + FCS_LEN) << 16) + 0x0010;
}
return ht_rate;
}
int carl9170_update_beacon(struct ar9170 *ar, const bool submit)
{
struct sk_buff *skb = NULL;
struct carl9170_vif_info *cvif;
struct ieee80211_tx_info *txinfo;
struct ieee80211_tx_rate *rate;
__le32 *data, *old = NULL;
unsigned int plcp, power, chains;
u32 word, ht1, off, addr, len;
u32 word, ht1, plcp, off, addr, len;
int i = 0, err = 0;
bool ht_rate;
rcu_read_lock();
cvif = rcu_dereference(ar->beacon_iter);
retry:
if (ar->vifs == 0 || !cvif)
cvif = carl9170_pick_beaconing_vif(ar);
if (!cvif)
goto out_unlock;
list_for_each_entry_continue_rcu(cvif, &ar->vif_list, list) {
if (cvif->active && cvif->enable_beacon)
goto found;
}
if (!ar->beacon_enabled || i++)
goto out_unlock;
goto retry;
found:
rcu_assign_pointer(ar->beacon_iter, cvif);
skb = ieee80211_beacon_get_tim(ar->hw, carl9170_get_vif(cvif),
NULL, NULL);
@ -1558,7 +1615,6 @@ int carl9170_update_beacon(struct ar9170 *ar, const bool submit)
goto err_free;
}
txinfo = IEEE80211_SKB_CB(skb);
spin_lock_bh(&ar->beacon_lock);
data = (__le32 *)skb->data;
if (cvif->beacon)
@ -1588,43 +1644,14 @@ int carl9170_update_beacon(struct ar9170 *ar, const bool submit)
goto err_unlock;
}
ht1 = AR9170_MAC_BCN_HT1_TX_ANT0;
rate = &txinfo->control.rates[0];
carl9170_tx_rate_tpc_chains(ar, txinfo, rate, &plcp, &power, &chains);
if (!(txinfo->control.rates[0].flags & IEEE80211_TX_RC_MCS)) {
if (plcp <= AR9170_TX_PHY_RATE_CCK_11M)
plcp |= ((skb->len + FCS_LEN) << (3 + 16)) + 0x0400;
else
plcp |= ((skb->len + FCS_LEN) << 16) + 0x0010;
} else {
ht1 |= AR9170_MAC_BCN_HT1_HT_EN;
if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
plcp |= AR9170_MAC_BCN_HT2_SGI;
if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) {
ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_SHARED;
plcp |= AR9170_MAC_BCN_HT2_BW40;
}
if (rate->flags & IEEE80211_TX_RC_DUP_DATA) {
ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_DUP;
plcp |= AR9170_MAC_BCN_HT2_BW40;
}
SET_VAL(AR9170_MAC_BCN_HT2_LEN, plcp, skb->len + FCS_LEN);
}
SET_VAL(AR9170_MAC_BCN_HT1_PWR_CTRL, ht1, 7);
SET_VAL(AR9170_MAC_BCN_HT1_TPC, ht1, power);
SET_VAL(AR9170_MAC_BCN_HT1_CHAIN_MASK, ht1, chains);
if (chains == AR9170_TX_PHY_TXCHAIN_2)
ht1 |= AR9170_MAC_BCN_HT1_TX_ANT1;
ht_rate = carl9170_tx_beacon_physet(ar, skb, &ht1, &plcp);
carl9170_async_regwrite_begin(ar);
carl9170_async_regwrite(AR9170_MAC_REG_BCN_HT1, ht1);
if (!(txinfo->control.rates[0].flags & IEEE80211_TX_RC_MCS))
carl9170_async_regwrite(AR9170_MAC_REG_BCN_PLCP, plcp);
else
if (ht_rate)
carl9170_async_regwrite(AR9170_MAC_REG_BCN_HT2, plcp);
else
carl9170_async_regwrite(AR9170_MAC_REG_BCN_PLCP, plcp);
for (i = 0; i < DIV_ROUND_UP(skb->len, 4); i++) {
/*

View file

@ -1,7 +1,7 @@
#ifndef __CARL9170_SHARED_VERSION_H
#define __CARL9170_SHARED_VERSION_H
#define CARL9170FW_VERSION_YEAR 12
#define CARL9170FW_VERSION_MONTH 7
#define CARL9170FW_VERSION_DAY 7
#define CARL9170FW_VERSION_GIT "1.9.6"
#define CARL9170FW_VERSION_MONTH 12
#define CARL9170FW_VERSION_DAY 15
#define CARL9170FW_VERSION_GIT "1.9.7"
#endif /* __CARL9170_SHARED_VERSION_H */

View file

@ -195,8 +195,6 @@ ath_reg_apply_beaconing_flags(struct wiphy *wiphy,
const struct ieee80211_reg_rule *reg_rule;
struct ieee80211_channel *ch;
unsigned int i;
u32 bandwidth = 0;
int r;
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
@ -214,11 +212,8 @@ ath_reg_apply_beaconing_flags(struct wiphy *wiphy,
continue;
if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
r = freq_reg_info(wiphy,
ch->center_freq,
bandwidth,
&reg_rule);
if (r)
reg_rule = freq_reg_info(wiphy, ch->center_freq);
if (IS_ERR(reg_rule))
continue;
/*
* If 11d had a rule for this channel ensure
@ -254,8 +249,6 @@ ath_reg_apply_active_scan_flags(struct wiphy *wiphy,
struct ieee80211_supported_band *sband;
struct ieee80211_channel *ch;
const struct ieee80211_reg_rule *reg_rule;
u32 bandwidth = 0;
int r;
sband = wiphy->bands[IEEE80211_BAND_2GHZ];
if (!sband)
@ -283,16 +276,16 @@ ath_reg_apply_active_scan_flags(struct wiphy *wiphy,
*/
ch = &sband->channels[11]; /* CH 12 */
r = freq_reg_info(wiphy, ch->center_freq, bandwidth, &reg_rule);
if (!r) {
reg_rule = freq_reg_info(wiphy, ch->center_freq);
if (!IS_ERR(reg_rule)) {
if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
}
ch = &sband->channels[12]; /* CH 13 */
r = freq_reg_info(wiphy, ch->center_freq, bandwidth, &reg_rule);
if (!r) {
reg_rule = freq_reg_info(wiphy, ch->center_freq);
if (!IS_ERR(reg_rule)) {
if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
@ -363,9 +356,9 @@ static u16 ath_regd_find_country_by_name(char *alpha2)
return -1;
}
int ath_reg_notifier_apply(struct wiphy *wiphy,
struct regulatory_request *request,
struct ath_regulatory *reg)
void ath_reg_notifier_apply(struct wiphy *wiphy,
struct regulatory_request *request,
struct ath_regulatory *reg)
{
struct ath_common *common = container_of(reg, struct ath_common,
regulatory);
@ -380,7 +373,7 @@ int ath_reg_notifier_apply(struct wiphy *wiphy,
* any pending requests in the queue.
*/
if (!request)
return 0;
return;
switch (request->initiator) {
case NL80211_REGDOM_SET_BY_CORE:
@ -416,8 +409,6 @@ int ath_reg_notifier_apply(struct wiphy *wiphy,
break;
}
return 0;
}
EXPORT_SYMBOL(ath_reg_notifier_apply);
@ -507,8 +498,8 @@ ath_get_regpair(int regdmn)
static int
ath_regd_init_wiphy(struct ath_regulatory *reg,
struct wiphy *wiphy,
int (*reg_notifier)(struct wiphy *wiphy,
struct regulatory_request *request))
void (*reg_notifier)(struct wiphy *wiphy,
struct regulatory_request *request))
{
const struct ieee80211_regdomain *regd;
@ -628,8 +619,8 @@ static int __ath_regd_init(struct ath_regulatory *reg)
int
ath_regd_init(struct ath_regulatory *reg,
struct wiphy *wiphy,
int (*reg_notifier)(struct wiphy *wiphy,
struct regulatory_request *request))
void (*reg_notifier)(struct wiphy *wiphy,
struct regulatory_request *request))
{
struct ath_common *common = container_of(reg, struct ath_common,
regulatory);

View file

@ -252,12 +252,12 @@ enum CountryCode {
bool ath_is_world_regd(struct ath_regulatory *reg);
bool ath_is_49ghz_allowed(u16 redomain);
int ath_regd_init(struct ath_regulatory *reg, struct wiphy *wiphy,
int (*reg_notifier)(struct wiphy *wiphy,
struct regulatory_request *request));
void (*reg_notifier)(struct wiphy *wiphy,
struct regulatory_request *request));
u32 ath_regd_get_band_ctl(struct ath_regulatory *reg,
enum ieee80211_band band);
int ath_reg_notifier_apply(struct wiphy *wiphy,
struct regulatory_request *request,
struct ath_regulatory *reg);
void ath_reg_notifier_apply(struct wiphy *wiphy,
struct regulatory_request *request,
struct ath_regulatory *reg);
#endif

View file

@ -3226,8 +3226,6 @@ struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent(
{
struct nphy_gain_ctl_workaround_entry *e;
u8 phy_idx;
u8 tr_iso = ghz5 ? dev->dev->bus_sprom->fem.ghz5.tr_iso :
dev->dev->bus_sprom->fem.ghz2.tr_iso;
if (!ghz5 && dev->phy.rev >= 6 && dev->phy.radio_rev == 11)
return &nphy_gain_ctl_wa_phy6_radio11_ghz2;
@ -3249,6 +3247,10 @@ struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent(
!b43_channel_type_is_40mhz(dev->phy.channel_type))
e->cliplo_gain = 0x2d;
} else if (!ghz5 && dev->phy.rev >= 5) {
static const int gain_data[] = {0x0062, 0x0064, 0x006a, 0x106a,
0x106c, 0x1074, 0x107c, 0x207c};
u8 tr_iso = dev->dev->bus_sprom->fem.ghz2.tr_iso;
if (ext_lna) {
e->rfseq_init[0] &= ~0x4000;
e->rfseq_init[1] &= ~0x4000;
@ -3256,26 +3258,10 @@ struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent(
e->rfseq_init[3] &= ~0x4000;
e->init_gain &= ~0x4000;
}
switch (tr_iso) {
case 0:
e->cliplo_gain = 0x0062;
case 1:
e->cliplo_gain = 0x0064;
case 2:
e->cliplo_gain = 0x006a;
case 3:
e->cliplo_gain = 0x106a;
case 4:
e->cliplo_gain = 0x106c;
case 5:
e->cliplo_gain = 0x1074;
case 6:
e->cliplo_gain = 0x107c;
case 7:
e->cliplo_gain = 0x207c;
default:
e->cliplo_gain = 0x106a;
}
if (tr_iso > 7)
tr_iso = 3;
e->cliplo_gain = gain_data[tr_iso];
} else if (ghz5 && dev->phy.rev == 4 && ext_lna) {
e->rfseq_init[0] &= ~0x4000;
e->rfseq_init[1] &= ~0x4000;

View file

@ -15,8 +15,6 @@
*/
/* ****************** SDIO CARD Interface Functions **************************/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/types.h>
#include <linux/netdevice.h>
#include <linux/export.h>

View file

@ -14,8 +14,6 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/types.h>
#include <linux/netdevice.h>
#include <linux/mmc/sdio.h>

View file

@ -39,6 +39,7 @@
#define BRCMF_C_GET_BSSID 23
#define BRCMF_C_GET_SSID 25
#define BRCMF_C_SET_SSID 26
#define BRCMF_C_TERMINATED 28
#define BRCMF_C_GET_CHANNEL 29
#define BRCMF_C_SET_CHANNEL 30
#define BRCMF_C_GET_SRL 31
@ -480,36 +481,14 @@ struct brcmf_pub {
unsigned long drv_version; /* Version of dongle-resident driver */
u8 mac[ETH_ALEN]; /* MAC address obtained from dongle */
/* Additional stats for the bus level */
/* Multicast data packets sent to dongle */
unsigned long tx_multicast;
/* Packets flushed due to unscheduled sendup thread */
unsigned long rx_flushed;
/* Number of times dpc scheduled by watchdog timer */
unsigned long wd_dpc_sched;
/* Number of flow control pkts recvd */
unsigned long fc_packets;
/* Last error return */
int bcmerror;
/* Last error from dongle */
int dongle_error;
/* Suspend disable flag flag */
int suspend_disable_flag; /* "1" to disable all extra powersaving
during suspend */
int in_suspend; /* flag set to 1 when early suspend called */
int dtim_skip; /* dtim skip , default 0 means wake each dtim */
struct brcmf_if *iflist[BRCMF_MAX_IFS];
struct mutex proto_block;
unsigned char proto_buf[BRCMF_DCMD_MAXLEN];
u8 macvalue[ETH_ALEN];
atomic_t pend_8021x_cnt;
wait_queue_head_t pend_8021x_wait;
@ -519,11 +498,6 @@ struct brcmf_pub {
#endif
};
struct bcmevent_name {
uint event;
const char *name;
};
struct brcmf_if_event {
u8 ifidx;
u8 action;
@ -557,13 +531,6 @@ struct brcmf_if {
u8 mac_addr[ETH_ALEN];
};
static inline s32 brcmf_ndev_bssidx(struct net_device *ndev)
{
struct brcmf_if *ifp = netdev_priv(ndev);
return ifp->bssidx;
}
extern const struct bcmevent_name bcmevent_names[];
extern int brcmf_netdev_wait_pend8021x(struct net_device *ndev);
@ -576,6 +543,10 @@ extern int brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx,
extern int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
void *buf, uint len);
/* Remove any protocol-specific data header. */
extern int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx,
struct sk_buff *rxp);
extern int brcmf_net_attach(struct brcmf_if *ifp);
extern struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx,
s32 bssidx, char *name, u8 *mac_addr);

View file

@ -130,31 +130,18 @@ int brcmf_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint len)
* interface functions from common layer
*/
/* Remove any protocol-specific data header. */
extern int brcmf_proto_hdrpull(struct device *dev, int *ifidx,
struct sk_buff *rxp);
extern bool brcmf_c_prec_enq(struct device *dev, struct pktq *q,
struct sk_buff *pkt, int prec);
/* Receive frame for delivery to OS. Callee disposes of rxp. */
extern void brcmf_rx_frame(struct device *dev, u8 ifidx,
struct sk_buff_head *rxlist);
static inline void brcmf_rx_packet(struct device *dev, int ifidx,
struct sk_buff *pkt)
{
struct sk_buff_head q;
skb_queue_head_init(&q);
skb_queue_tail(&q, pkt);
brcmf_rx_frame(dev, ifidx, &q);
}
extern void brcmf_rx_frames(struct device *dev, struct sk_buff_head *rxlist);
/* Indication from bus module regarding presence/insertion of dongle. */
extern int brcmf_attach(uint bus_hdrlen, struct device *dev);
/* Indication from bus module regarding removal/absence of dongle */
extern void brcmf_detach(struct device *dev);
/* Indication from bus module that dongle should be reset */
extern void brcmf_dev_reset(struct device *dev);
/* Indication from bus module to change flow-control state */
extern void brcmf_txflowblock(struct device *dev, bool state);

View file

@ -19,8 +19,6 @@
* For certain dcmd codes, the dongle interprets string data from the host.
******************************************************************************/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/types.h>
#include <linux/netdevice.h>
@ -94,8 +92,6 @@ struct brcmf_proto_bdc_header {
struct brcmf_proto {
u16 reqid;
u8 pending;
u32 lastcmd;
u8 bus_header[BUS_HEADER_LEN];
struct brcmf_proto_cdc_dcmd msg;
unsigned char buf[BRCMF_DCMD_MAXLEN + ROUND_UP_MARGIN];
@ -107,7 +103,7 @@ static int brcmf_proto_cdc_msg(struct brcmf_pub *drvr)
int len = le32_to_cpu(prot->msg.len) +
sizeof(struct brcmf_proto_cdc_dcmd);
brcmf_dbg(TRACE, "Enter\n");
brcmf_dbg(CDC, "Enter\n");
/* NOTE : cdc->msg.len holds the desired length of the buffer to be
* returned. Only up to CDC_MAX_MSG_SIZE of this buffer area
@ -125,7 +121,7 @@ static int brcmf_proto_cdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len)
int ret;
struct brcmf_proto *prot = drvr->prot;
brcmf_dbg(TRACE, "Enter\n");
brcmf_dbg(CDC, "Enter\n");
len += sizeof(struct brcmf_proto_cdc_dcmd);
do {
ret = brcmf_bus_rxctl(drvr->bus_if, (unsigned char *)&prot->msg,
@ -147,20 +143,7 @@ brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
int ret = 0, retries = 0;
u32 id, flags;
brcmf_dbg(TRACE, "Enter\n");
brcmf_dbg(CTL, "cmd %d len %d\n", cmd, len);
/* Respond "bcmerror" and "bcmerrorstr" with local cache */
if (cmd == BRCMF_C_GET_VAR && buf) {
if (!strcmp((char *)buf, "bcmerrorstr")) {
strncpy((char *)buf, "bcm_error",
BCME_STRLEN);
goto done;
} else if (!strcmp((char *)buf, "bcmerror")) {
*(int *)buf = drvr->dongle_error;
goto done;
}
}
brcmf_dbg(CDC, "Enter, cmd %d len %d\n", cmd, len);
memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd));
@ -210,11 +193,8 @@ brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
}
/* Check the ERROR flag */
if (flags & CDC_DCMD_ERROR) {
if (flags & CDC_DCMD_ERROR)
ret = le32_to_cpu(msg->status);
/* Cache error from dongle */
drvr->dongle_error = ret;
}
done:
return ret;
@ -228,8 +208,7 @@ int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
int ret = 0;
u32 flags, id;
brcmf_dbg(TRACE, "Enter\n");
brcmf_dbg(CTL, "cmd %d len %d\n", cmd, len);
brcmf_dbg(CDC, "Enter, cmd %d len %d\n", cmd, len);
memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd));
@ -262,11 +241,8 @@ int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
}
/* Check the ERROR flag */
if (flags & CDC_DCMD_ERROR) {
if (flags & CDC_DCMD_ERROR)
ret = le32_to_cpu(msg->status);
/* Cache error from dongle */
drvr->dongle_error = ret;
}
done:
return ret;
@ -287,7 +263,7 @@ void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx,
{
struct brcmf_proto_bdc_header *h;
brcmf_dbg(TRACE, "Enter\n");
brcmf_dbg(CDC, "Enter\n");
/* Push BDC header used to convey priority for buses that don't */
@ -305,14 +281,12 @@ void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx,
BDC_SET_IF_IDX(h, ifidx);
}
int brcmf_proto_hdrpull(struct device *dev, int *ifidx,
int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx,
struct sk_buff *pktbuf)
{
struct brcmf_proto_bdc_header *h;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_pub *drvr = bus_if->drvr;
brcmf_dbg(TRACE, "Enter\n");
brcmf_dbg(CDC, "Enter\n");
/* Pop BDC header used to convey priority for buses that don't */
@ -338,7 +312,7 @@ int brcmf_proto_hdrpull(struct device *dev, int *ifidx,
}
if (h->flags & BDC_FLAG_SUM_GOOD) {
brcmf_dbg(INFO, "%s: BDC packet received with good rx-csum, flags 0x%x\n",
brcmf_dbg(CDC, "%s: BDC rcv, good checksum, flags 0x%x\n",
brcmf_ifname(drvr, *ifidx), h->flags);
pkt_set_sum_good(pktbuf, true);
}
@ -348,6 +322,8 @@ int brcmf_proto_hdrpull(struct device *dev, int *ifidx,
skb_pull(pktbuf, BDC_HEADER_LEN);
skb_pull(pktbuf, h->data_offset << 2);
if (pktbuf->len == 0)
return -ENODATA;
return 0;
}

View file

@ -14,8 +14,6 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/netdevice.h>

View file

@ -18,21 +18,26 @@
#define _BRCMF_DBG_H_
/* message levels */
#define BRCMF_TRACE_VAL 0x0002
#define BRCMF_INFO_VAL 0x0004
#define BRCMF_DATA_VAL 0x0008
#define BRCMF_CTL_VAL 0x0010
#define BRCMF_TIMER_VAL 0x0020
#define BRCMF_HDRS_VAL 0x0040
#define BRCMF_BYTES_VAL 0x0080
#define BRCMF_INTR_VAL 0x0100
#define BRCMF_GLOM_VAL 0x0200
#define BRCMF_EVENT_VAL 0x0400
#define BRCMF_BTA_VAL 0x0800
#define BRCMF_FIL_VAL 0x1000
#define BRCMF_USB_VAL 0x2000
#define BRCMF_SCAN_VAL 0x4000
#define BRCMF_CONN_VAL 0x8000
#define BRCMF_TRACE_VAL 0x00000002
#define BRCMF_INFO_VAL 0x00000004
#define BRCMF_DATA_VAL 0x00000008
#define BRCMF_CTL_VAL 0x00000010
#define BRCMF_TIMER_VAL 0x00000020
#define BRCMF_HDRS_VAL 0x00000040
#define BRCMF_BYTES_VAL 0x00000080
#define BRCMF_INTR_VAL 0x00000100
#define BRCMF_GLOM_VAL 0x00000200
#define BRCMF_EVENT_VAL 0x00000400
#define BRCMF_BTA_VAL 0x00000800
#define BRCMF_FIL_VAL 0x00001000
#define BRCMF_USB_VAL 0x00002000
#define BRCMF_SCAN_VAL 0x00004000
#define BRCMF_CONN_VAL 0x00008000
#define BRCMF_CDC_VAL 0x00010000
/* set default print format */
#undef pr_fmt
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
/* Macro for error messages. net_ratelimit() is used when driver
* debugging is not selected. When debugging the driver error

View file

@ -14,8 +14,6 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/etherdevice.h>
#include <linux/module.h>
@ -162,28 +160,31 @@ static void brcmf_netdev_set_multicast_list(struct net_device *ndev)
schedule_work(&ifp->multicast_work);
}
static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
struct net_device *ndev)
{
int ret;
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_pub *drvr = ifp->drvr;
struct ethhdr *eh;
brcmf_dbg(TRACE, "Enter\n");
/* Reject if down */
if (!drvr->bus_if->drvr_up ||
(drvr->bus_if->state != BRCMF_BUS_DATA)) {
brcmf_err("xmit rejected drvup=%d state=%d\n",
drvr->bus_if->drvr_up,
drvr->bus_if->state);
/* Can the device send data? */
if (drvr->bus_if->state != BRCMF_BUS_DATA) {
brcmf_err("xmit rejected state=%d\n", drvr->bus_if->state);
netif_stop_queue(ndev);
return -ENODEV;
dev_kfree_skb(skb);
ret = -ENODEV;
goto done;
}
if (!drvr->iflist[ifp->idx]) {
brcmf_err("bad ifidx %d\n", ifp->idx);
netif_stop_queue(ndev);
return -ENODEV;
dev_kfree_skb(skb);
ret = -ENODEV;
goto done;
}
/* Make sure there's enough room for any header */
@ -204,17 +205,20 @@ static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
}
}
/* Update multicast statistic */
if (skb->len >= ETH_ALEN) {
u8 *pktdata = (u8 *)(skb->data);
struct ethhdr *eh = (struct ethhdr *)pktdata;
if (is_multicast_ether_addr(eh->h_dest))
drvr->tx_multicast++;
if (ntohs(eh->h_proto) == ETH_P_PAE)
atomic_inc(&drvr->pend_8021x_cnt);
/* validate length for ether packet */
if (skb->len < sizeof(*eh)) {
ret = -EINVAL;
dev_kfree_skb(skb);
goto done;
}
/* handle ethernet header */
eh = (struct ethhdr *)(skb->data);
if (is_multicast_ether_addr(eh->h_dest))
drvr->tx_multicast++;
if (ntohs(eh->h_proto) == ETH_P_PAE)
atomic_inc(&drvr->pend_8021x_cnt);
/* If the protocol uses a data header, apply it */
brcmf_proto_hdrpush(drvr, ifp->idx, skb);
@ -228,7 +232,7 @@ static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
drvr->bus_if->dstats.tx_packets++;
/* Return ok: we always eat the packet */
return 0;
return NETDEV_TX_OK;
}
void brcmf_txflowblock(struct device *dev, bool state)
@ -250,8 +254,7 @@ void brcmf_txflowblock(struct device *dev, bool state)
}
}
void brcmf_rx_frame(struct device *dev, u8 ifidx,
struct sk_buff_head *skb_list)
void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list)
{
unsigned char *eth;
uint len;
@ -259,12 +262,24 @@ void brcmf_rx_frame(struct device *dev, u8 ifidx,
struct brcmf_if *ifp;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_pub *drvr = bus_if->drvr;
u8 ifidx;
int ret;
brcmf_dbg(TRACE, "Enter\n");
skb_queue_walk_safe(skb_list, skb, pnext) {
skb_unlink(skb, skb_list);
/* process and remove protocol-specific header
*/
ret = brcmf_proto_hdrpull(drvr, &ifidx, skb);
if (ret < 0) {
if (ret != -ENODATA)
bus_if->dstats.rx_errors++;
brcmu_pkt_buf_free_skb(skb);
continue;
}
/* Get the protocol, maintain skb around eth_type_trans()
* The main reason for this hack is for the limitation of
* Linux 2.4 where 'eth_type_trans' uses the
@ -328,13 +343,13 @@ void brcmf_rx_frame(struct device *dev, u8 ifidx,
void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
{
uint ifidx;
u8 ifidx;
struct ethhdr *eh;
u16 type;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_pub *drvr = bus_if->drvr;
brcmf_proto_hdrpull(dev, &ifidx, txp);
brcmf_proto_hdrpull(drvr, &ifidx, txp);
eh = (struct ethhdr *)(txp->data);
type = ntohs(eh->h_proto);
@ -452,7 +467,7 @@ static int brcmf_ethtool(struct brcmf_if *ifp, void __user *uaddr)
sprintf(info.version, "%lu", drvr->drv_version);
if (copy_to_user(uaddr, &info, sizeof(info)))
return -EFAULT;
brcmf_dbg(CTL, "given %*s, returning %s\n",
brcmf_dbg(TRACE, "given %*s, returning %s\n",
(int)sizeof(drvname), drvname, info.driver);
break;
@ -572,14 +587,9 @@ static int brcmf_netdev_open(struct net_device *ndev)
/* Get current TOE mode from dongle */
if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0
&& (toe_ol & TOE_TX_CSUM_OL) != 0)
drvr->iflist[ifp->idx]->ndev->features |=
NETIF_F_IP_CSUM;
ndev->features |= NETIF_F_IP_CSUM;
else
drvr->iflist[ifp->idx]->ndev->features &=
~NETIF_F_IP_CSUM;
/* make sure RF is ready for work */
brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
ndev->features &= ~NETIF_F_IP_CSUM;
/* Allow transmit calls */
netif_start_queue(ndev);
@ -847,6 +857,17 @@ static void brcmf_bus_detach(struct brcmf_pub *drvr)
}
}
void brcmf_dev_reset(struct device *dev)
{
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_pub *drvr = bus_if->drvr;
if (drvr == NULL)
return;
brcmf_fil_cmd_int_set(drvr->iflist[0], BRCMF_C_TERMINATED, 1);
}
void brcmf_detach(struct device *dev)
{
int i;
@ -868,9 +889,8 @@ void brcmf_detach(struct device *dev)
brcmf_bus_detach(drvr);
if (drvr->prot) {
if (drvr->prot)
brcmf_proto_detach(drvr);
}
brcmf_debugfs_detach(drvr);
bus_if->drvr = NULL;

View file

@ -14,8 +14,6 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
@ -1169,7 +1167,6 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
int errcode;
u8 doff, sfdoff;
int ifidx = 0;
bool usechain = bus->use_rxchain;
struct brcmf_sdio_read rd_new;
@ -1388,13 +1385,6 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
skb_unlink(pfirst, &bus->glom);
brcmu_pkt_buf_free_skb(pfirst);
continue;
} else if (brcmf_proto_hdrpull(bus->sdiodev->dev,
&ifidx, pfirst) != 0) {
brcmf_err("rx protocol error\n");
bus->sdiodev->bus_if->dstats.rx_errors++;
skb_unlink(pfirst, &bus->glom);
brcmu_pkt_buf_free_skb(pfirst);
continue;
}
brcmf_dbg_hex_dump(BRCMF_GLOM_ON(),
@ -1407,7 +1397,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
}
/* sent any remaining packets up */
if (bus->glom.qlen)
brcmf_rx_frame(bus->sdiodev->dev, ifidx, &bus->glom);
brcmf_rx_frames(bus->sdiodev->dev, &bus->glom);
bus->sdcnt.rxglomframes++;
bus->sdcnt.rxglompkts += bus->glom.qlen;
@ -1558,10 +1548,10 @@ static void brcmf_pad(struct brcmf_sdio *bus, u16 *pad, u16 *rdlen)
static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
{
struct sk_buff *pkt; /* Packet for event or data frames */
struct sk_buff_head pktlist; /* needed for bus interface */
u16 pad; /* Number of pad bytes to read */
uint rxleft = 0; /* Remaining number of frames allowed */
int sdret; /* Return code from calls */
int ifidx = 0;
uint rxcount = 0; /* Total frames read */
struct brcmf_sdio_read *rd = &bus->cur_read, rd_new;
u8 head_read = 0;
@ -1760,15 +1750,11 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
if (pkt->len == 0) {
brcmu_pkt_buf_free_skb(pkt);
continue;
} else if (brcmf_proto_hdrpull(bus->sdiodev->dev, &ifidx,
pkt) != 0) {
brcmf_err("rx protocol error\n");
brcmu_pkt_buf_free_skb(pkt);
bus->sdiodev->bus_if->dstats.rx_errors++;
continue;
}
brcmf_rx_packet(bus->sdiodev->dev, ifidx, pkt);
skb_queue_head_init(&pktlist);
skb_queue_tail(&pktlist, pkt);
brcmf_rx_frames(bus->sdiodev->dev, &pktlist);
}
rxcount = maxframes - rxleft;

View file

@ -15,8 +15,6 @@
*/
/* ***** SDIO interface chip backplane handle functions ***** */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/types.h>
#include <linux/netdevice.h>
#include <linux/mmc/card.h>

View file

@ -443,14 +443,15 @@ static void brcmf_usb_rx_complete(struct urb *urb)
struct brcmf_usbreq *req = (struct brcmf_usbreq *)urb->context;
struct brcmf_usbdev_info *devinfo = req->devinfo;
struct sk_buff *skb;
int ifidx = 0;
struct sk_buff_head skbq;
brcmf_dbg(USB, "Enter, urb->status=%d\n", urb->status);
brcmf_usb_del_fromq(devinfo, req);
skb = req->skb;
req->skb = NULL;
if (urb->status == 0) {
/* zero lenght packets indicate usb "failure". Do not refill */
if (urb->status == 0 && urb->actual_length) {
devinfo->bus_pub.bus->dstats.rx_packets++;
} else {
devinfo->bus_pub.bus->dstats.rx_errors++;
@ -460,13 +461,10 @@ static void brcmf_usb_rx_complete(struct urb *urb)
}
if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) {
skb_queue_head_init(&skbq);
skb_queue_tail(&skbq, skb);
skb_put(skb, urb->actual_length);
if (brcmf_proto_hdrpull(devinfo->dev, &ifidx, skb) != 0) {
brcmf_err("rx protocol error\n");
brcmu_pkt_buf_free_skb(skb);
devinfo->bus_pub.bus->dstats.rx_errors++;
} else
brcmf_rx_packet(devinfo->dev, ifidx, skb);
brcmf_rx_frames(devinfo->dev, &skbq);
brcmf_usb_rx_refill(devinfo, req);
} else {
brcmu_pkt_buf_free_skb(skb);
@ -1520,10 +1518,23 @@ static void brcmf_release_fw(struct list_head *q)
}
}
static int brcmf_usb_reset_device(struct device *dev, void *notused)
{
/* device past is the usb interface so we
* need to use parent here.
*/
brcmf_dev_reset(dev->parent);
return 0;
}
void brcmf_usb_exit(void)
{
struct device_driver *drv = &brcmf_usbdrvr.drvwrap.driver;
int ret;
brcmf_dbg(USB, "Enter\n");
ret = driver_for_each_device(drv, NULL, NULL,
brcmf_usb_reset_device);
usb_deregister(&brcmf_usbdrvr);
brcmf_release_fw(&fw_image_list);
}

View file

@ -16,8 +16,6 @@
/* Toplevel file. Relies on dhd_linux.c to send commands to the dongle. */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/etherdevice.h>
#include <net/cfg80211.h>
@ -2011,67 +2009,6 @@ brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
return err;
}
static s32
brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *ndev,
const u8 *addr,
const struct cfg80211_bitrate_mask *mask)
{
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcm_rateset_le rateset_le;
s32 rate;
s32 val;
s32 err_bg;
s32 err_a;
u32 legacy;
s32 err = 0;
brcmf_dbg(TRACE, "Enter\n");
if (!check_vif_up(ifp->vif))
return -EIO;
/* addr param is always NULL. ignore it */
/* Get current rateset */
err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_CURR_RATESET,
&rateset_le, sizeof(rateset_le));
if (err) {
brcmf_err("could not get current rateset (%d)\n", err);
goto done;
}
legacy = ffs(mask->control[IEEE80211_BAND_2GHZ].legacy & 0xFFFF);
if (!legacy)
legacy = ffs(mask->control[IEEE80211_BAND_5GHZ].legacy &
0xFFFF);
val = wl_g_rates[legacy - 1].bitrate * 100000;
if (val < le32_to_cpu(rateset_le.count))
/* Select rate by rateset index */
rate = rateset_le.rates[val] & 0x7f;
else
/* Specified rate in bps */
rate = val / 500000;
brcmf_dbg(CONN, "rate %d mbps\n", rate / 2);
/*
*
* Set rate override,
* Since the is a/b/g-blind, both a/bg_rate are enforced.
*/
err_bg = brcmf_fil_iovar_int_set(ifp, "bg_rate", rate);
err_a = brcmf_fil_iovar_int_set(ifp, "a_rate", rate);
if (err_bg && err_a) {
brcmf_err("could not set fixed rate (%d) (%d)\n", err_bg,
err_a);
err = err_bg | err_a;
}
done:
brcmf_dbg(TRACE, "Exit\n");
return err;
}
static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
struct brcmf_bss_info_le *bi)
{
@ -3704,7 +3641,6 @@ static struct cfg80211_ops wl_cfg80211_ops = {
.set_default_key = brcmf_cfg80211_config_default_key,
.set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
.set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
.set_bitrate_mask = brcmf_cfg80211_set_bitrate_mask,
.connect = brcmf_cfg80211_connect,
.disconnect = brcmf_cfg80211_disconnect,
.suspend = brcmf_cfg80211_suspend,
@ -4330,9 +4266,8 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
}
static s32
brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)
{
struct brcmf_if *ifp = netdev_priv(ndev);
s32 err = 0;
__le32 roamtrigger[2];
__le32 roam_delta[2];
@ -4383,10 +4318,9 @@ brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
}
static s32
brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
brcmf_dongle_scantime(struct brcmf_if *ifp, s32 scan_assoc_time,
s32 scan_unassoc_time, s32 scan_passive_time)
{
struct brcmf_if *ifp = netdev_priv(ndev);
s32 err = 0;
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
@ -4456,6 +4390,7 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
{
struct net_device *ndev;
struct wireless_dev *wdev;
struct brcmf_if *ifp;
s32 power_mode;
s32 err = 0;
@ -4464,35 +4399,34 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
ndev = cfg_to_ndev(cfg);
wdev = ndev->ieee80211_ptr;
ifp = netdev_priv(ndev);
brcmf_dongle_scantime(ndev, WL_SCAN_CHANNEL_TIME,
WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
/* make sure RF is ready for work */
brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
brcmf_dongle_scantime(ifp, WL_SCAN_CHANNEL_TIME,
WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PM,
power_mode);
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
if (err)
goto default_conf_out;
brcmf_dbg(INFO, "power save set to %s\n",
(power_mode ? "enabled" : "disabled"));
err = brcmf_dongle_roam(ndev, (cfg->roam_on ? 0 : 1),
WL_BEACON_TIMEOUT);
err = brcmf_dongle_roam(ifp, (cfg->roam_on ? 0 : 1), WL_BEACON_TIMEOUT);
if (err)
goto default_conf_out;
err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
NULL, NULL);
if (err && err != -EINPROGRESS)
if (err)
goto default_conf_out;
err = brcmf_dongle_probecap(cfg);
if (err)
goto default_conf_out;
/* -EINPROGRESS: Call commit handler */
default_conf_out:
cfg->dongle_up = true;
default_conf_out:
return err;
@ -4501,8 +4435,6 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
{
set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
if (ifp->idx)
return 0;
return brcmf_config_dongle(ifp->drvr->config);
}

View file

@ -961,7 +961,6 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
/* if acked then clear bit and free packet */
if ((bindex < AMPDU_TX_BA_MAX_WSIZE)
&& isset(bitmap, bindex)) {
ini->tx_in_transit--;
ini->txretry[index] = 0;
/*
@ -990,7 +989,6 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
if (retry && (ini->txretry[index] < (int)retry_limit)) {
int ret;
ini->txretry[index]++;
ini->tx_in_transit--;
ret = brcms_c_txfifo(wlc, queue, p);
/*
* We shouldn't be out of space in the DMA
@ -1000,7 +998,6 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
WARN_ONCE(ret, "queue %d out of txds\n", queue);
} else {
/* Retry timeout */
ini->tx_in_transit--;
ieee80211_tx_info_clear_status(tx_info);
tx_info->status.ampdu_ack_len = 0;
tx_info->status.ampdu_len = 1;
@ -1009,8 +1006,8 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
skb_pull(p, D11_PHY_HDR_LEN);
skb_pull(p, D11_TXH_LEN);
brcms_dbg_ht(wlc->hw->d11core,
"BA Timeout, seq %d, in_transit %d\n",
seq, ini->tx_in_transit);
"BA Timeout, seq %d\n",
seq);
ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw,
p);
}

View file

@ -670,7 +670,7 @@ brcms_reg_apply_beaconing_flags(struct wiphy *wiphy,
struct ieee80211_supported_band *sband;
struct ieee80211_channel *ch;
const struct ieee80211_reg_rule *rule;
int band, i, ret;
int band, i;
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
sband = wiphy->bands[band];
@ -685,9 +685,8 @@ brcms_reg_apply_beaconing_flags(struct wiphy *wiphy,
continue;
if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
ret = freq_reg_info(wiphy, ch->center_freq,
0, &rule);
if (ret)
rule = freq_reg_info(wiphy, ch->center_freq);
if (IS_ERR(rule))
continue;
if (!(rule->flags & NL80211_RRF_NO_IBSS))
@ -703,8 +702,8 @@ brcms_reg_apply_beaconing_flags(struct wiphy *wiphy,
}
}
static int brcms_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
static void brcms_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
{
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct brcms_info *wl = hw->priv;
@ -745,8 +744,6 @@ static int brcms_reg_notifier(struct wiphy *wiphy,
if (wlc->pub->_nbands > 1 || wlc->band->bandtype == BRCM_BAND_2G)
wlc_phy_chanspec_ch14_widefilter_set(wlc->band->pi,
brcms_c_japan_ccode(request->alpha2));
return 0;
}
void brcms_c_regd_init(struct brcms_c_info *wlc)

View file

@ -362,8 +362,11 @@ brcms_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
return -EOPNOTSUPP;
}
spin_lock_bh(&wl->lock);
memcpy(wl->pub->cur_etheraddr, vif->addr, sizeof(vif->addr));
wl->mute_tx = false;
brcms_c_mute(wl->wlc, false);
spin_unlock_bh(&wl->lock);
return 0;
}
@ -668,7 +671,9 @@ brcms_ops_ampdu_action(struct ieee80211_hw *hw,
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
case IEEE80211_AMPDU_TX_STOP:
case IEEE80211_AMPDU_TX_STOP_CONT:
case IEEE80211_AMPDU_TX_STOP_FLUSH:
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
spin_lock_bh(&wl->lock);
brcms_c_ampdu_flush(wl->wlc, sta, tid);
spin_unlock_bh(&wl->lock);
@ -1407,9 +1412,10 @@ void brcms_add_timer(struct brcms_timer *t, uint ms, int periodic)
#endif
t->ms = ms;
t->periodic = (bool) periodic;
t->set = true;
atomic_inc(&t->wl->callbacks);
if (!t->set) {
t->set = true;
atomic_inc(&t->wl->callbacks);
}
ieee80211_queue_delayed_work(hw, &t->dly_wrk, msecs_to_jiffies(ms));
}

View file

@ -2473,6 +2473,7 @@ static void brcms_b_tx_fifo_resume(struct brcms_hardware *wlc_hw,
static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool mute_tx)
{
static const u8 null_ether_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
u8 *ethaddr = wlc_hw->wlc->pub->cur_etheraddr;
if (mute_tx) {
/* suspend tx fifos */
@ -2482,8 +2483,7 @@ static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool mute_tx)
brcms_b_tx_fifo_suspend(wlc_hw, TX_AC_VI_FIFO);
/* zero the address match register so we do not send ACKs */
brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET,
null_ether_addr);
brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET, null_ether_addr);
} else {
/* resume tx fifos */
brcms_b_tx_fifo_resume(wlc_hw, TX_DATA_FIFO);
@ -2492,8 +2492,7 @@ static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool mute_tx)
brcms_b_tx_fifo_resume(wlc_hw, TX_AC_VI_FIFO);
/* Restore address */
brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET,
wlc_hw->etheraddr);
brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET, ethaddr);
}
wlc_phy_mute_upd(wlc_hw->band->pi, mute_tx, 0);
@ -7633,7 +7632,7 @@ brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound)
uint n = 0;
uint bound_limit = bound ? RXBND : -1;
bool morepending;
bool morepending = false;
skb_queue_head_init(&recv_frames);

View file

@ -36,7 +36,6 @@
/* structure to store per-tid state for the ampdu initiator */
struct scb_ampdu_tid_ini {
u8 tx_in_transit; /* number of pending mpdus in transit in driver */
u8 tid; /* initiator tid for easy lookup */
/* tx retry count; indexed by seq modulo */
u8 txretry[AMPDU_TX_BA_MAX_WSIZE];

View file

@ -3474,6 +3474,7 @@ struct ieee80211_ops il3945_mac_ops = {
.sta_add = il3945_mac_sta_add,
.sta_remove = il_mac_sta_remove,
.tx_last_beacon = il_mac_tx_last_beacon,
.flush = il_mac_flush,
};
static int
@ -3548,7 +3549,8 @@ il3945_setup_mac(struct il_priv *il)
hw->vif_data_size = sizeof(struct il_vif_priv);
/* Tell mac80211 our characteristics */
hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SPECTRUM_MGMT;
hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SPECTRUM_MGMT |
IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
@ -3557,6 +3559,8 @@ il3945_setup_mac(struct il_priv *il)
WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_DISABLE_BEACON_HINTS |
WIPHY_FLAG_IBSS_RSN;
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX_3945;
/* we create the 802.11 header and a zero-length SSID element */
hw->wiphy->max_scan_ie_len = IL3945_MAX_PROBE_REQUEST - 24 - 2;

View file

@ -5712,8 +5712,8 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length)
hw->flags =
IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_AMPDU_AGGREGATION |
IEEE80211_HW_NEED_DTIM_PERIOD | IEEE80211_HW_SPECTRUM_MGMT |
IEEE80211_HW_REPORTS_TX_ACK_STATUS;
IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
if (il->cfg->sku & IL_SKU_N)
hw->flags |=
IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
@ -5968,7 +5968,9 @@ il4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
D_HT("start Tx\n");
ret = il4965_tx_agg_start(il, vif, sta, tid, ssn);
break;
case IEEE80211_AMPDU_TX_STOP:
case IEEE80211_AMPDU_TX_STOP_CONT:
case IEEE80211_AMPDU_TX_STOP_FLUSH:
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
D_HT("stop Tx\n");
ret = il4965_tx_agg_stop(il, vif, sta, tid);
if (test_bit(S_EXIT_PENDING, &il->status))
@ -6306,6 +6308,7 @@ const struct ieee80211_ops il4965_mac_ops = {
.sta_remove = il_mac_sta_remove,
.channel_switch = il4965_mac_channel_switch,
.tx_last_beacon = il_mac_tx_last_beacon,
.flush = il_mac_flush,
};
static int
@ -6553,6 +6556,7 @@ il4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
il4965_prepare_card_hw(il);
if (!il->hw_ready) {
IL_WARN("Failed, HW not ready\n");
err = -EIO;
goto out_iounmap;
}

View file

@ -3958,17 +3958,21 @@ il_connection_init_rx_config(struct il_priv *il)
memset(&il->staging, 0, sizeof(il->staging));
if (!il->vif) {
switch (il->iw_mode) {
case NL80211_IFTYPE_UNSPECIFIED:
il->staging.dev_type = RXON_DEV_TYPE_ESS;
} else if (il->vif->type == NL80211_IFTYPE_STATION) {
break;
case NL80211_IFTYPE_STATION:
il->staging.dev_type = RXON_DEV_TYPE_ESS;
il->staging.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK;
} else if (il->vif->type == NL80211_IFTYPE_ADHOC) {
break;
case NL80211_IFTYPE_ADHOC:
il->staging.dev_type = RXON_DEV_TYPE_IBSS;
il->staging.flags = RXON_FLG_SHORT_PREAMBLE_MSK;
il->staging.filter_flags =
RXON_FILTER_BCON_AWARE_MSK | RXON_FILTER_ACCEPT_GRP_MSK;
} else {
break;
default:
IL_ERR("Unsupported interface type %d\n", il->vif->type);
return;
}
@ -4550,8 +4554,7 @@ il_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
EXPORT_SYMBOL(il_mac_add_interface);
static void
il_teardown_interface(struct il_priv *il, struct ieee80211_vif *vif,
bool mode_change)
il_teardown_interface(struct il_priv *il, struct ieee80211_vif *vif)
{
lockdep_assert_held(&il->mutex);
@ -4560,9 +4563,7 @@ il_teardown_interface(struct il_priv *il, struct ieee80211_vif *vif,
il_force_scan_end(il);
}
if (!mode_change)
il_set_mode(il);
il_set_mode(il);
}
void
@ -4575,8 +4576,8 @@ il_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
WARN_ON(il->vif != vif);
il->vif = NULL;
il_teardown_interface(il, vif, false);
il->iw_mode = NL80211_IFTYPE_UNSPECIFIED;
il_teardown_interface(il, vif);
memset(il->bssid, 0, ETH_ALEN);
D_MAC80211("leave\n");
@ -4685,18 +4686,10 @@ il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
}
/* success */
il_teardown_interface(il, vif, true);
vif->type = newtype;
vif->p2p = false;
err = il_set_mode(il);
WARN_ON(err);
/*
* We've switched internally, but submitting to the
* device may have failed for some reason. Mask this
* error, because otherwise mac80211 will not switch
* (and set the interface type back) and we'll be
* out of sync with it.
*/
il->iw_mode = newtype;
il_teardown_interface(il, vif);
err = 0;
out:
@ -4707,6 +4700,42 @@ il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
}
EXPORT_SYMBOL(il_mac_change_interface);
void
il_mac_flush(struct ieee80211_hw *hw, bool drop)
{
struct il_priv *il = hw->priv;
unsigned long timeout = jiffies + msecs_to_jiffies(500);
int i;
mutex_lock(&il->mutex);
D_MAC80211("enter\n");
if (il->txq == NULL)
goto out;
for (i = 0; i < il->hw_params.max_txq_num; i++) {
struct il_queue *q;
if (i == il->cmd_queue)
continue;
q = &il->txq[i].q;
if (q->read_ptr == q->write_ptr)
continue;
if (time_after(jiffies, timeout)) {
IL_ERR("Failed to flush queue %d\n", q->id);
break;
}
msleep(20);
}
out:
D_MAC80211("leave\n");
mutex_unlock(&il->mutex);
}
EXPORT_SYMBOL(il_mac_flush);
/*
* On every watchdog tick we check (latest) time stamp. If it does not
* change during timeout period and queue is not empty we reset firmware.

View file

@ -1723,6 +1723,7 @@ void il_mac_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
int il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum nl80211_iftype newtype, bool newp2p);
void il_mac_flush(struct ieee80211_hw *hw, bool drop);
int il_alloc_txq_mem(struct il_priv *il);
void il_free_txq_mem(struct il_priv *il);

View file

@ -3695,7 +3695,7 @@ struct iwl_bt_uart_msg {
u8 frame5;
u8 frame6;
u8 frame7;
} __attribute__((packed));
} __packed;
struct iwl_bt_coex_profile_notif {
struct iwl_bt_uart_msg last_bt_uart_msg;
@ -3703,7 +3703,7 @@ struct iwl_bt_coex_profile_notif {
u8 bt_traffic_load; /* 0 .. 3? */
u8 bt_ci_compliance; /* 0 - not complied, 1 - complied */
u8 reserved;
} __attribute__((packed));
} __packed;
#define IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS 0
#define IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_MSK 0x1
@ -3752,7 +3752,7 @@ enum bt_coex_prio_table_priorities {
struct iwl_bt_coex_prio_table_cmd {
u8 prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX];
} __attribute__((packed));
} __packed;
#define IWL_BT_COEX_ENV_CLOSE 0
#define IWL_BT_COEX_ENV_OPEN 1
@ -3764,7 +3764,7 @@ struct iwl_bt_coex_prot_env_cmd {
u8 action; /* 0 = closed, 1 = open */
u8 type; /* 0 .. 15 */
u8 reserved[2];
} __attribute__((packed));
} __packed;
/*
* REPLY_D3_CONFIG

View file

@ -157,7 +157,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
sram = priv->dbgfs_sram_offset & ~0x3;
/* read the first u32 from sram */
val = iwl_read_targ_mem(priv->trans, sram);
val = iwl_trans_read_mem32(priv->trans, sram);
for (; len; len--) {
/* put the address at the start of every line */
@ -176,7 +176,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
if (++offset == 4) {
sram += 4;
offset = 0;
val = iwl_read_targ_mem(priv->trans, sram);
val = iwl_trans_read_mem32(priv->trans, sram);
}
/* put in extra spaces and split lines for human readability */

View file

@ -69,7 +69,7 @@ static const struct ieee80211_tpt_blink iwl_blink[] = {
/* Set led register off */
void iwlagn_led_enable(struct iwl_priv *priv)
{
iwl_write32(priv->trans, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
iwl_write32(priv->trans, CSR_LED_REG, CSR_LED_REG_TURN_ON);
}
/*

View file

@ -206,7 +206,8 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
#ifdef CONFIG_PM_SLEEP
if (priv->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
priv->trans->ops->wowlan_suspend &&
priv->trans->ops->d3_suspend &&
priv->trans->ops->d3_resume &&
device_can_wakeup(priv->trans->dev)) {
hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
WIPHY_WOWLAN_DISCONNECT |
@ -426,7 +427,7 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
if (ret)
goto error;
iwl_trans_wowlan_suspend(priv->trans);
iwl_trans_d3_suspend(priv->trans);
goto out;
@ -459,11 +460,11 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
base = priv->device_pointers.error_event_table;
if (iwlagn_hw_valid_rtc_data_addr(base)) {
spin_lock_irqsave(&priv->trans->reg_lock, flags);
ret = iwl_grab_nic_access_silent(priv->trans);
if (likely(ret == 0)) {
if (iwl_trans_grab_nic_access(priv->trans, true)) {
iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, base);
status = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
iwl_release_nic_access(priv->trans);
iwl_trans_release_nic_access(priv->trans);
ret = 0;
}
spin_unlock_irqrestore(&priv->trans->reg_lock, flags);
@ -479,7 +480,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
}
if (priv->wowlan_sram)
_iwl_read_targ_mem_dwords(
iwl_trans_read_mem(
priv->trans, 0x800000,
priv->wowlan_sram,
img->sec[IWL_UCODE_SECTION_DATA].len / 4);
@ -520,9 +521,6 @@ static void iwlagn_mac_tx(struct ieee80211_hw *hw,
{
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
IWL_DEBUG_TX(priv, "dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate);
if (iwlagn_tx_skb(priv, control->sta, skb))
ieee80211_free_txskb(hw, skb);
}
@ -679,7 +677,9 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
IWL_DEBUG_HT(priv, "start Tx\n");
ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn);
break;
case IEEE80211_AMPDU_TX_STOP:
case IEEE80211_AMPDU_TX_STOP_CONT:
case IEEE80211_AMPDU_TX_STOP_FLUSH:
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
IWL_DEBUG_HT(priv, "stop Tx\n");
ret = iwlagn_tx_agg_stop(priv, vif, sta, tid);
if ((ret == 0) && (priv->agg_tids_count > 0)) {

View file

@ -354,7 +354,7 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
/* Make sure device is powered up for SRAM reads */
spin_lock_irqsave(&priv->trans->reg_lock, reg_flags);
if (unlikely(!iwl_grab_nic_access(priv->trans))) {
if (!iwl_trans_grab_nic_access(priv->trans, false)) {
spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags);
return;
}
@ -388,7 +388,7 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
}
}
/* Allow device to power down */
iwl_release_nic_access(priv->trans);
iwl_trans_release_nic_access(priv->trans);
spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags);
}
@ -408,7 +408,8 @@ static void iwl_continuous_event_trace(struct iwl_priv *priv)
base = priv->device_pointers.log_event_table;
if (iwlagn_hw_valid_rtc_data_addr(base)) {
iwl_read_targ_mem_bytes(priv->trans, base, &read, sizeof(read));
iwl_trans_read_mem_bytes(priv->trans, base,
&read, sizeof(read));
capacity = read.capacity;
mode = read.mode;
num_wraps = read.wrap_counter;
@ -1627,7 +1628,7 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv)
}
/*TODO: Update dbgfs with ISR error stats obtained below */
iwl_read_targ_mem_bytes(trans, base, &table, sizeof(table));
iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table));
if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
IWL_ERR(trans, "Start IWL Error Log Dump:\n");
@ -1717,7 +1718,7 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
/* Make sure device is powered up for SRAM reads */
spin_lock_irqsave(&trans->reg_lock, reg_flags);
if (unlikely(!iwl_grab_nic_access(trans)))
if (!iwl_trans_grab_nic_access(trans, false))
goto out_unlock;
/* Set starting address; reads will auto-increment */
@ -1756,7 +1757,7 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
}
/* Allow device to power down */
iwl_release_nic_access(trans);
iwl_trans_release_nic_access(trans);
out_unlock:
spin_unlock_irqrestore(&trans->reg_lock, reg_flags);
return pos;
@ -1835,10 +1836,10 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
}
/* event log header */
capacity = iwl_read_targ_mem(trans, base);
mode = iwl_read_targ_mem(trans, base + (1 * sizeof(u32)));
num_wraps = iwl_read_targ_mem(trans, base + (2 * sizeof(u32)));
next_entry = iwl_read_targ_mem(trans, base + (3 * sizeof(u32)));
capacity = iwl_trans_read_mem32(trans, base);
mode = iwl_trans_read_mem32(trans, base + (1 * sizeof(u32)));
num_wraps = iwl_trans_read_mem32(trans, base + (2 * sizeof(u32)));
next_entry = iwl_trans_read_mem32(trans, base + (3 * sizeof(u32)));
if (capacity > logsize) {
IWL_ERR(priv, "Log capacity %d is bogus, limit to %d "

View file

@ -186,8 +186,8 @@ static void iwl_tt_check_exit_ct_kill(unsigned long data)
}
iwl_read32(priv->trans, CSR_UCODE_DRV_GP1);
spin_lock_irqsave(&priv->trans->reg_lock, flags);
if (likely(iwl_grab_nic_access(priv->trans)))
iwl_release_nic_access(priv->trans);
if (iwl_trans_grab_nic_access(priv->trans, false))
iwl_trans_release_nic_access(priv->trans);
spin_unlock_irqrestore(&priv->trans->reg_lock, flags);
/* Reschedule the ct_kill timer to occur in

View file

@ -231,13 +231,11 @@ static void iwlagn_tx_cmd_build_hwcrypto(struct iwl_priv *priv,
memcpy(tx_cmd->key, keyconf->key, keyconf->keylen);
if (info->flags & IEEE80211_TX_CTL_AMPDU)
tx_cmd->tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK;
IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n");
break;
case WLAN_CIPHER_SUITE_TKIP:
tx_cmd->sec_ctl = TX_CMD_SEC_TKIP;
ieee80211_get_tkip_p2k(keyconf, skb_frag, tx_cmd->key);
IWL_DEBUG_TX(priv, "tx_cmd with tkip hwcrypto\n");
break;
case WLAN_CIPHER_SUITE_WEP104:
@ -355,8 +353,6 @@ int iwlagn_tx_skb(struct iwl_priv *priv,
}
}
IWL_DEBUG_TX(priv, "station Id %d\n", sta_id);
if (sta)
sta_priv = (void *)sta->drv_priv;
@ -472,6 +468,9 @@ int iwlagn_tx_skb(struct iwl_priv *priv,
WARN_ON_ONCE(is_agg &&
priv->queue_to_mac80211[txq_id] != info->hw_queue);
IWL_DEBUG_TX(priv, "TX to [%d|%d] Q:%d - seq: 0x%x\n", sta_id, tid,
txq_id, seq_number);
if (iwl_trans_tx(priv->trans, skb, dev_cmd, txq_id))
goto drop_unlock_sta;
@ -541,9 +540,9 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
spin_lock_bh(&priv->sta_lock);
tid_data = &priv->tid_data[sta_id][tid];
txq_id = priv->tid_data[sta_id][tid].agg.txq_id;
txq_id = tid_data->agg.txq_id;
switch (priv->tid_data[sta_id][tid].agg.state) {
switch (tid_data->agg.state) {
case IWL_EMPTYING_HW_QUEUE_ADDBA:
/*
* This can happen if the peer stops aggregation
@ -563,9 +562,9 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
case IWL_AGG_ON:
break;
default:
IWL_WARN(priv, "Stopping AGG while state not ON "
"or starting for %d on %d (%d)\n", sta_id, tid,
priv->tid_data[sta_id][tid].agg.state);
IWL_WARN(priv,
"Stopping AGG while state not ON or starting for %d on %d (%d)\n",
sta_id, tid, tid_data->agg.state);
spin_unlock_bh(&priv->sta_lock);
return 0;
}
@ -578,12 +577,11 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
"stopping AGG on STA/TID %d/%d but hwq %d not used\n",
sta_id, tid, txq_id);
} else if (tid_data->agg.ssn != tid_data->next_reclaimed) {
IWL_DEBUG_TX_QUEUES(priv, "Can't proceed: ssn %d, "
"next_recl = %d\n",
IWL_DEBUG_TX_QUEUES(priv,
"Can't proceed: ssn %d, next_recl = %d\n",
tid_data->agg.ssn,
tid_data->next_reclaimed);
priv->tid_data[sta_id][tid].agg.state =
IWL_EMPTYING_HW_QUEUE_DELBA;
tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_DELBA;
spin_unlock_bh(&priv->sta_lock);
return 0;
}
@ -591,8 +589,8 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
IWL_DEBUG_TX_QUEUES(priv, "Can proceed: ssn = next_recl = %d\n",
tid_data->agg.ssn);
turn_off:
agg_state = priv->tid_data[sta_id][tid].agg.state;
priv->tid_data[sta_id][tid].agg.state = IWL_AGG_OFF;
agg_state = tid_data->agg.state;
tid_data->agg.state = IWL_AGG_OFF;
spin_unlock_bh(&priv->sta_lock);
@ -954,12 +952,6 @@ static void iwl_rx_reply_tx_agg(struct iwl_priv *priv,
if (status & (AGG_TX_STATE_FEW_BYTES_MSK |
AGG_TX_STATE_ABORT_MSK))
continue;
IWL_DEBUG_TX_REPLY(priv, "status %s (0x%08x), "
"try-count (0x%08x)\n",
iwl_get_agg_tx_fail_reason(fstatus),
fstatus & AGG_TX_STATUS_MSK,
fstatus & AGG_TX_TRY_MSK);
}
}
@ -1079,6 +1071,8 @@ static void iwlagn_set_tx_status(struct iwl_priv *priv,
{
u16 status = le16_to_cpu(tx_resp->status.status);
info->flags &= ~IEEE80211_TX_CTL_AMPDU;
info->status.rates[0].count = tx_resp->failure_frame + 1;
info->flags |= iwl_tx_status_to_mac80211(status);
iwlagn_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags),
@ -1223,16 +1217,27 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
next_reclaimed);
}
WARN_ON(!is_agg && freed != 1);
if (!is_agg && freed != 1)
IWL_ERR(priv, "Q: %d, freed %d\n", txq_id, freed);
/*
* An offchannel frame can be send only on the AUX queue, where
* there is no aggregation (and reordering) so it only is single
* skb is expected to be processed.
*/
WARN_ON(is_offchannel_skb && freed != 1);
if (is_offchannel_skb && freed != 1)
IWL_ERR(priv, "OFFCHANNEL SKB freed %d\n", freed);
}
IWL_DEBUG_TX_REPLY(priv, "TXQ %d status %s (0x%08x)\n", txq_id,
iwl_get_tx_fail_reason(status), status);
IWL_DEBUG_TX_REPLY(priv,
"\t\t\t\tinitial_rate 0x%x retries %d, idx=%d ssn=%d seq_ctl=0x%x\n",
le32_to_cpu(tx_resp->rate_n_flags),
tx_resp->failure_frame, SEQ_TO_INDEX(sequence), ssn,
le16_to_cpu(tx_resp->seq_ctl));
iwl_check_abort_status(priv, tx_resp->frame_count, status);
spin_unlock(&priv->sta_lock);

View file

@ -286,89 +286,6 @@ static int iwl_alive_notify(struct iwl_priv *priv)
return iwl_send_calib_results(priv);
}
/**
* iwl_verify_inst_sparse - verify runtime uCode image in card vs. host,
* using sample data 100 bytes apart. If these sample points are good,
* it's a pretty good bet that everything between them is good, too.
*/
static int iwl_verify_sec_sparse(struct iwl_priv *priv,
const struct fw_desc *fw_desc)
{
__le32 *image = (__le32 *)fw_desc->data;
u32 len = fw_desc->len;
u32 val;
u32 i;
IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len);
for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
/* read data comes through single port, auto-incr addr */
/* NOTE: Use the debugless read so we don't flood kernel log
* if IWL_DL_IO is set */
iwl_write_direct32(priv->trans, HBUS_TARG_MEM_RADDR,
i + fw_desc->offset);
val = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
if (val != le32_to_cpu(*image))
return -EIO;
}
return 0;
}
static void iwl_print_mismatch_sec(struct iwl_priv *priv,
const struct fw_desc *fw_desc)
{
__le32 *image = (__le32 *)fw_desc->data;
u32 len = fw_desc->len;
u32 val;
u32 offs;
int errors = 0;
IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len);
iwl_write_direct32(priv->trans, HBUS_TARG_MEM_RADDR,
fw_desc->offset);
for (offs = 0;
offs < len && errors < 20;
offs += sizeof(u32), image++) {
/* read data comes through single port, auto-incr addr */
val = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
if (val != le32_to_cpu(*image)) {
IWL_ERR(priv, "uCode INST section at "
"offset 0x%x, is 0x%x, s/b 0x%x\n",
offs, val, le32_to_cpu(*image));
errors++;
}
}
}
/**
* iwl_verify_ucode - determine which instruction image is in SRAM,
* and verify its contents
*/
static int iwl_verify_ucode(struct iwl_priv *priv,
enum iwl_ucode_type ucode_type)
{
const struct fw_img *img = iwl_get_ucode_image(priv, ucode_type);
if (!img) {
IWL_ERR(priv, "Invalid ucode requested (%d)\n", ucode_type);
return -EINVAL;
}
if (!iwl_verify_sec_sparse(priv, &img->sec[IWL_UCODE_SECTION_INST])) {
IWL_DEBUG_FW(priv, "uCode is good in inst SRAM\n");
return 0;
}
IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n");
iwl_print_mismatch_sec(priv, &img->sec[IWL_UCODE_SECTION_INST]);
return -EIO;
}
struct iwl_alive_data {
bool valid;
u8 subtype;
@ -426,7 +343,7 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv,
alive_cmd, ARRAY_SIZE(alive_cmd),
iwl_alive_fn, &alive_data);
ret = iwl_trans_start_fw(priv->trans, fw);
ret = iwl_trans_start_fw(priv->trans, fw, false);
if (ret) {
priv->cur_ucode = old_type;
iwl_remove_notification(&priv->notif_wait, &alive_wait);
@ -450,18 +367,7 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv,
return -EIO;
}
/*
* This step takes a long time (60-80ms!!) and
* WoWLAN image should be loaded quickly, so
* skip it for WoWLAN.
*/
if (ucode_type != IWL_UCODE_WOWLAN) {
ret = iwl_verify_ucode(priv, ucode_type);
if (ret) {
priv->cur_ucode = old_type;
return ret;
}
/* delay a bit to give rfkill time to run */
msleep(5);
}

View file

@ -381,8 +381,8 @@
/* LED */
#define CSR_LED_BSM_CTRL_MSK (0xFFFFFFDF)
#define CSR_LED_REG_TRUN_ON (0x78)
#define CSR_LED_REG_TRUN_OFF (0x38)
#define CSR_LED_REG_TURN_ON (0x60)
#define CSR_LED_REG_TURN_OFF (0x20)
/* ANA_PLL */
#define CSR50_ANA_PLL_CFG_VAL (0x00880300)

View file

@ -225,6 +225,8 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl)
#define FH_RSCSR_CHNL0_RBDCB_WPTR_REG (FH_MEM_RSCSR_CHNL0 + 0x008)
#define FH_RSCSR_CHNL0_WPTR (FH_RSCSR_CHNL0_RBDCB_WPTR_REG)
#define FW_RSCSR_CHNL0_RXDCB_RDPTR_REG (FH_MEM_RSCSR_CHNL0 + 0x00c)
#define FH_RSCSR_CHNL0_RDPTR FW_RSCSR_CHNL0_RXDCB_RDPTR_REG
/**
* Rx Config/Status Registers (RCSR)
@ -257,6 +259,8 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl)
#define FH_MEM_RCSR_CHNL0 (FH_MEM_RCSR_LOWER_BOUND)
#define FH_MEM_RCSR_CHNL0_CONFIG_REG (FH_MEM_RCSR_CHNL0)
#define FH_MEM_RCSR_CHNL0_RBDCB_WPTR (FH_MEM_RCSR_CHNL0 + 0x8)
#define FH_MEM_RCSR_CHNL0_FLUSH_RB_REQ (FH_MEM_RCSR_CHNL0 + 0x10)
#define FH_RCSR_CHNL0_RX_CONFIG_RB_TIMEOUT_MSK (0x00000FF0) /* bits 4-11 */
#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_MSK (0x00001000) /* bits 12 */

View file

@ -35,12 +35,12 @@
#define IWL_POLL_INTERVAL 10 /* microseconds */
static inline void __iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask)
void __iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask)
{
iwl_write32(trans, reg, iwl_read32(trans, reg) | mask);
}
static inline void __iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask)
void __iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask)
{
iwl_write32(trans, reg, iwl_read32(trans, reg) & ~mask);
}
@ -99,86 +99,16 @@ int iwl_poll_bit(struct iwl_trans *trans, u32 addr,
}
EXPORT_SYMBOL_GPL(iwl_poll_bit);
int iwl_grab_nic_access_silent(struct iwl_trans *trans)
{
int ret;
lockdep_assert_held(&trans->reg_lock);
/* this bit wakes up the NIC */
__iwl_set_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
/*
* These bits say the device is running, and should keep running for
* at least a short while (at least as long as MAC_ACCESS_REQ stays 1),
* but they do not indicate that embedded SRAM is restored yet;
* 3945 and 4965 have volatile SRAM, and must save/restore contents
* to/from host DRAM when sleeping/waking for power-saving.
* Each direction takes approximately 1/4 millisecond; with this
* overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a
* series of register accesses are expected (e.g. reading Event Log),
* to keep device from sleeping.
*
* CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that
* SRAM is okay/restored. We don't check that here because this call
* is just for hardware register access; but GP1 MAC_SLEEP check is a
* good idea before accessing 3945/4965 SRAM (e.g. reading Event Log).
*
* 5000 series and later (including 1000 series) have non-volatile SRAM,
* and do not save/restore SRAM when power cycling.
*/
ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
(CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000);
if (ret < 0) {
iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI);
return -EIO;
}
return 0;
}
EXPORT_SYMBOL_GPL(iwl_grab_nic_access_silent);
bool iwl_grab_nic_access(struct iwl_trans *trans)
{
int ret = iwl_grab_nic_access_silent(trans);
if (unlikely(ret)) {
u32 val = iwl_read32(trans, CSR_GP_CNTRL);
WARN_ONCE(1, "Timeout waiting for hardware access "
"(CSR_GP_CNTRL 0x%08x)\n", val);
return false;
}
return true;
}
EXPORT_SYMBOL_GPL(iwl_grab_nic_access);
void iwl_release_nic_access(struct iwl_trans *trans)
{
lockdep_assert_held(&trans->reg_lock);
__iwl_clear_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
/*
* Above we read the CSR_GP_CNTRL register, which will flush
* any previous writes, but we need the write that clears the
* MAC_ACCESS_REQ bit to be performed before any other writes
* scheduled on different CPUs (after we drop reg_lock).
*/
mmiowb();
}
EXPORT_SYMBOL_GPL(iwl_release_nic_access);
u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg)
{
u32 value;
u32 value = 0x5a5a5a5a;
unsigned long flags;
spin_lock_irqsave(&trans->reg_lock, flags);
iwl_grab_nic_access(trans);
value = iwl_read32(trans, reg);
iwl_release_nic_access(trans);
if (iwl_trans_grab_nic_access(trans, false)) {
value = iwl_read32(trans, reg);
iwl_trans_release_nic_access(trans);
}
spin_unlock_irqrestore(&trans->reg_lock, flags);
return value;
@ -190,9 +120,9 @@ void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value)
unsigned long flags;
spin_lock_irqsave(&trans->reg_lock, flags);
if (likely(iwl_grab_nic_access(trans))) {
if (iwl_trans_grab_nic_access(trans, false)) {
iwl_write32(trans, reg, value);
iwl_release_nic_access(trans);
iwl_trans_release_nic_access(trans);
}
spin_unlock_irqrestore(&trans->reg_lock, flags);
}
@ -230,12 +160,13 @@ static inline void __iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val)
u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs)
{
unsigned long flags;
u32 val;
u32 val = 0x5a5a5a5a;
spin_lock_irqsave(&trans->reg_lock, flags);
iwl_grab_nic_access(trans);
val = __iwl_read_prph(trans, ofs);
iwl_release_nic_access(trans);
if (iwl_trans_grab_nic_access(trans, false)) {
val = __iwl_read_prph(trans, ofs);
iwl_trans_release_nic_access(trans);
}
spin_unlock_irqrestore(&trans->reg_lock, flags);
return val;
}
@ -246,9 +177,9 @@ void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val)
unsigned long flags;
spin_lock_irqsave(&trans->reg_lock, flags);
if (likely(iwl_grab_nic_access(trans))) {
if (iwl_trans_grab_nic_access(trans, false)) {
__iwl_write_prph(trans, ofs, val);
iwl_release_nic_access(trans);
iwl_trans_release_nic_access(trans);
}
spin_unlock_irqrestore(&trans->reg_lock, flags);
}
@ -259,10 +190,10 @@ void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
unsigned long flags;
spin_lock_irqsave(&trans->reg_lock, flags);
if (likely(iwl_grab_nic_access(trans))) {
if (iwl_trans_grab_nic_access(trans, false)) {
__iwl_write_prph(trans, ofs,
__iwl_read_prph(trans, ofs) | mask);
iwl_release_nic_access(trans);
iwl_trans_release_nic_access(trans);
}
spin_unlock_irqrestore(&trans->reg_lock, flags);
}
@ -274,10 +205,10 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs,
unsigned long flags;
spin_lock_irqsave(&trans->reg_lock, flags);
if (likely(iwl_grab_nic_access(trans))) {
if (iwl_trans_grab_nic_access(trans, false)) {
__iwl_write_prph(trans, ofs,
(__iwl_read_prph(trans, ofs) & mask) | bits);
iwl_release_nic_access(trans);
iwl_trans_release_nic_access(trans);
}
spin_unlock_irqrestore(&trans->reg_lock, flags);
}
@ -289,66 +220,11 @@ void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
u32 val;
spin_lock_irqsave(&trans->reg_lock, flags);
if (likely(iwl_grab_nic_access(trans))) {
if (iwl_trans_grab_nic_access(trans, false)) {
val = __iwl_read_prph(trans, ofs);
__iwl_write_prph(trans, ofs, (val & ~mask));
iwl_release_nic_access(trans);
iwl_trans_release_nic_access(trans);
}
spin_unlock_irqrestore(&trans->reg_lock, flags);
}
EXPORT_SYMBOL_GPL(iwl_clear_bits_prph);
void _iwl_read_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
void *buf, int dwords)
{
unsigned long flags;
int offs;
u32 *vals = buf;
spin_lock_irqsave(&trans->reg_lock, flags);
if (likely(iwl_grab_nic_access(trans))) {
iwl_write32(trans, HBUS_TARG_MEM_RADDR, addr);
for (offs = 0; offs < dwords; offs++)
vals[offs] = iwl_read32(trans, HBUS_TARG_MEM_RDAT);
iwl_release_nic_access(trans);
}
spin_unlock_irqrestore(&trans->reg_lock, flags);
}
EXPORT_SYMBOL_GPL(_iwl_read_targ_mem_dwords);
u32 iwl_read_targ_mem(struct iwl_trans *trans, u32 addr)
{
u32 value;
_iwl_read_targ_mem_dwords(trans, addr, &value, 1);
return value;
}
EXPORT_SYMBOL_GPL(iwl_read_targ_mem);
int _iwl_write_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
const void *buf, int dwords)
{
unsigned long flags;
int offs, result = 0;
const u32 *vals = buf;
spin_lock_irqsave(&trans->reg_lock, flags);
if (likely(iwl_grab_nic_access(trans))) {
iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr);
for (offs = 0; offs < dwords; offs++)
iwl_write32(trans, HBUS_TARG_MEM_WDAT, vals[offs]);
iwl_release_nic_access(trans);
} else
result = -EBUSY;
spin_unlock_irqrestore(&trans->reg_lock, flags);
return result;
}
EXPORT_SYMBOL_GPL(_iwl_write_targ_mem_dwords);
int iwl_write_targ_mem(struct iwl_trans *trans, u32 addr, u32 val)
{
return _iwl_write_targ_mem_dwords(trans, addr, &val, 1);
}
EXPORT_SYMBOL_GPL(iwl_write_targ_mem);

View file

@ -53,6 +53,8 @@ static inline u32 iwl_read32(struct iwl_trans *trans, u32 ofs)
void iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask);
void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask);
void __iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask);
void __iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask);
void iwl_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value);
@ -61,10 +63,6 @@ int iwl_poll_bit(struct iwl_trans *trans, u32 addr,
int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask,
int timeout);
int iwl_grab_nic_access_silent(struct iwl_trans *trans);
bool iwl_grab_nic_access(struct iwl_trans *trans);
void iwl_release_nic_access(struct iwl_trans *trans);
u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg);
void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value);
@ -76,19 +74,4 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs,
u32 bits, u32 mask);
void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask);
void _iwl_read_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
void *buf, int dwords);
#define iwl_read_targ_mem_bytes(trans, addr, buf, bufsize) \
do { \
BUILD_BUG_ON((bufsize) % sizeof(u32)); \
_iwl_read_targ_mem_dwords(trans, addr, buf, \
(bufsize) / sizeof(u32));\
} while (0)
int _iwl_write_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
const void *buf, int dwords);
u32 iwl_read_targ_mem(struct iwl_trans *trans, u32 addr);
int iwl_write_targ_mem(struct iwl_trans *trans, u32 addr, u32 val);
#endif

View file

@ -467,18 +467,20 @@ static int iwl_test_indirect_read(struct iwl_test *tst, u32 addr, u32 size)
if (IWL_ABS_PRPH_START <= addr &&
addr < IWL_ABS_PRPH_START + PRPH_END) {
spin_lock_irqsave(&trans->reg_lock, flags);
iwl_grab_nic_access(trans);
if (!iwl_trans_grab_nic_access(trans, false)) {
spin_unlock_irqrestore(&trans->reg_lock, flags);
return -EIO;
}
iwl_write32(trans, HBUS_TARG_PRPH_RADDR,
addr | (3 << 24));
for (i = 0; i < size; i += 4)
*(u32 *)(tst->mem.addr + i) =
iwl_read32(trans, HBUS_TARG_PRPH_RDAT);
iwl_release_nic_access(trans);
iwl_trans_release_nic_access(trans);
spin_unlock_irqrestore(&trans->reg_lock, flags);
} else { /* target memory (SRAM) */
_iwl_read_targ_mem_dwords(trans, addr,
tst->mem.addr,
tst->mem.size / 4);
iwl_trans_read_mem(trans, addr, tst->mem.addr,
tst->mem.size / 4);
}
tst->mem.nchunks =
@ -501,28 +503,31 @@ static int iwl_test_indirect_write(struct iwl_test *tst, u32 addr,
if (IWL_ABS_PRPH_START <= addr &&
addr < IWL_ABS_PRPH_START + PRPH_END) {
/* Periphery writes can be 1-3 bytes long, or DWORDs */
if (size < 4) {
memcpy(&val, buf, size);
spin_lock_irqsave(&trans->reg_lock, flags);
iwl_grab_nic_access(trans);
iwl_write32(trans, HBUS_TARG_PRPH_WADDR,
(addr & 0x0000FFFF) |
((size - 1) << 24));
iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val);
iwl_release_nic_access(trans);
/* needed after consecutive writes w/o read */
mmiowb();
/* Periphery writes can be 1-3 bytes long, or DWORDs */
if (size < 4) {
memcpy(&val, buf, size);
spin_lock_irqsave(&trans->reg_lock, flags);
if (!iwl_trans_grab_nic_access(trans, false)) {
spin_unlock_irqrestore(&trans->reg_lock, flags);
} else {
if (size % 4)
return -EINVAL;
for (i = 0; i < size; i += 4)
iwl_write_prph(trans, addr+i,
*(u32 *)(buf+i));
return -EIO;
}
iwl_write32(trans, HBUS_TARG_PRPH_WADDR,
(addr & 0x0000FFFF) |
((size - 1) << 24));
iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val);
iwl_trans_release_nic_access(trans);
/* needed after consecutive writes w/o read */
mmiowb();
spin_unlock_irqrestore(&trans->reg_lock, flags);
} else {
if (size % 4)
return -EINVAL;
for (i = 0; i < size; i += 4)
iwl_write_prph(trans, addr+i,
*(u32 *)(buf+i));
}
} else if (iwl_test_valid_hw_addr(tst, addr)) {
_iwl_write_targ_mem_dwords(trans, addr, buf, size / 4);
iwl_trans_write_mem(trans, addr, buf, size / 4);
} else {
return -EINVAL;
}

View file

@ -307,6 +307,16 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r)
#define IWL_MAX_TID_COUNT 8
#define IWL_FRAME_LIMIT 64
/**
* enum iwl_wowlan_status - WoWLAN image/device status
* @IWL_D3_STATUS_ALIVE: firmware is still running after resume
* @IWL_D3_STATUS_RESET: device was reset while suspended
*/
enum iwl_d3_status {
IWL_D3_STATUS_ALIVE,
IWL_D3_STATUS_RESET,
};
/**
* struct iwl_trans_config - transport configuration
*
@ -321,6 +331,8 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r)
* @n_no_reclaim_cmds: # of commands in list
* @rx_buf_size_8k: 8 kB RX buffer size needed for A-MSDUs,
* if unset 4k will be the RX buffer size
* @bc_table_dword: set to true if the BC table expects the byte count to be
* in DWORD (as opposed to bytes)
* @queue_watchdog_timeout: time (in ms) after which queues
* are considered stuck and will trigger device restart
* @command_names: array of command names, must be 256 entries
@ -335,6 +347,7 @@ struct iwl_trans_config {
int n_no_reclaim_cmds;
bool rx_buf_size_8k;
bool bc_table_dword;
unsigned int queue_watchdog_timeout;
const char **command_names;
};
@ -360,9 +373,12 @@ struct iwl_trans;
* May sleep
* @stop_device:stops the whole device (embedded CPU put to reset)
* May sleep
* @wowlan_suspend: put the device into the correct mode for WoWLAN during
* @d3_suspend: put the device into the correct mode for WoWLAN during
* suspend. This is optional, if not implemented WoWLAN will not be
* supported. This callback may sleep.
* @d3_resume: resume the device after WoWLAN, enabling the opmode to
* talk to the WoWLAN image to get its status. This is optional, if not
* implemented WoWLAN will not be supported. This callback may sleep.
* @send_cmd:send a host command. Must return -ERFKILL if RFkill is asserted.
* If RFkill is asserted in the middle of a SYNC host command, it must
* return -ERFKILL straight away.
@ -387,20 +403,27 @@ struct iwl_trans;
* @read32: read a u32 register at offset ofs from the BAR
* @read_prph: read a DWORD from a periphery register
* @write_prph: write a DWORD to a periphery register
* @read_mem: read device's SRAM in DWORD
* @write_mem: write device's SRAM in DWORD. If %buf is %NULL, then the memory
* will be zeroed.
* @configure: configure parameters required by the transport layer from
* the op_mode. May be called several times before start_fw, can't be
* called after that.
* @set_pmi: set the power pmi state
* @grab_nic_access: wake the NIC to be able to access non-HBUS regs
* @release_nic_access: let the NIC go to sleep
*/
struct iwl_trans_ops {
int (*start_hw)(struct iwl_trans *iwl_trans);
void (*stop_hw)(struct iwl_trans *iwl_trans, bool op_mode_leaving);
int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw);
int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw,
bool run_in_rfkill);
void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr);
void (*stop_device)(struct iwl_trans *trans);
void (*wowlan_suspend)(struct iwl_trans *trans);
void (*d3_suspend)(struct iwl_trans *trans);
int (*d3_resume)(struct iwl_trans *trans, enum iwl_d3_status *status);
int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
@ -424,9 +447,15 @@ struct iwl_trans_ops {
u32 (*read32)(struct iwl_trans *trans, u32 ofs);
u32 (*read_prph)(struct iwl_trans *trans, u32 ofs);
void (*write_prph)(struct iwl_trans *trans, u32 ofs, u32 val);
int (*read_mem)(struct iwl_trans *trans, u32 addr,
void *buf, int dwords);
int (*write_mem)(struct iwl_trans *trans, u32 addr,
void *buf, int dwords);
void (*configure)(struct iwl_trans *trans,
const struct iwl_trans_config *trans_cfg);
void (*set_pmi)(struct iwl_trans *trans, bool state);
bool (*grab_nic_access)(struct iwl_trans *trans, bool silent);
void (*release_nic_access)(struct iwl_trans *trans);
};
/**
@ -528,13 +557,14 @@ static inline void iwl_trans_fw_alive(struct iwl_trans *trans, u32 scd_addr)
}
static inline int iwl_trans_start_fw(struct iwl_trans *trans,
const struct fw_img *fw)
const struct fw_img *fw,
bool run_in_rfkill)
{
might_sleep();
WARN_ON_ONCE(!trans->rx_mpdu_cmd);
return trans->ops->start_fw(trans, fw);
return trans->ops->start_fw(trans, fw, run_in_rfkill);
}
static inline void iwl_trans_stop_device(struct iwl_trans *trans)
@ -546,10 +576,17 @@ static inline void iwl_trans_stop_device(struct iwl_trans *trans)
trans->state = IWL_TRANS_NO_FW;
}
static inline void iwl_trans_wowlan_suspend(struct iwl_trans *trans)
static inline void iwl_trans_d3_suspend(struct iwl_trans *trans)
{
might_sleep();
trans->ops->wowlan_suspend(trans);
trans->ops->d3_suspend(trans);
}
static inline int iwl_trans_d3_resume(struct iwl_trans *trans,
enum iwl_d3_status *status)
{
might_sleep();
return trans->ops->d3_resume(trans, status);
}
static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
@ -636,7 +673,7 @@ static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans)
}
static inline int iwl_trans_dbgfs_register(struct iwl_trans *trans,
struct dentry *dir)
struct dentry *dir)
{
return trans->ops->dbgfs_register(trans, dir);
}
@ -679,11 +716,57 @@ static inline void iwl_trans_write_prph(struct iwl_trans *trans, u32 ofs,
return trans->ops->write_prph(trans, ofs, val);
}
static inline int iwl_trans_read_mem(struct iwl_trans *trans, u32 addr,
void *buf, int dwords)
{
return trans->ops->read_mem(trans, addr, buf, dwords);
}
#define iwl_trans_read_mem_bytes(trans, addr, buf, bufsize) \
do { \
if (__builtin_constant_p(bufsize)) \
BUILD_BUG_ON((bufsize) % sizeof(u32)); \
iwl_trans_read_mem(trans, addr, buf, (bufsize) / sizeof(u32));\
} while (0)
static inline u32 iwl_trans_read_mem32(struct iwl_trans *trans, u32 addr)
{
u32 value;
if (WARN_ON(iwl_trans_read_mem(trans, addr, &value, 1)))
return 0xa5a5a5a5;
return value;
}
static inline int iwl_trans_write_mem(struct iwl_trans *trans, u32 addr,
void *buf, int dwords)
{
return trans->ops->write_mem(trans, addr, buf, dwords);
}
static inline u32 iwl_trans_write_mem32(struct iwl_trans *trans, u32 addr,
u32 val)
{
return iwl_trans_write_mem(trans, addr, &val, 1);
}
static inline void iwl_trans_set_pmi(struct iwl_trans *trans, bool state)
{
trans->ops->set_pmi(trans, state);
}
#define iwl_trans_grab_nic_access(trans, silent) \
__cond_lock(nic_access, \
likely((trans)->ops->grab_nic_access(trans, silent)))
static inline void __releases(nic_access)
iwl_trans_release_nic_access(struct iwl_trans *trans)
{
trans->ops->release_nic_access(trans);
__release(nic_access);
}
/*****************************************************
* driver (transport) register/unregister functions
******************************************************/

View file

@ -222,8 +222,6 @@ struct iwl_txq {
* @rx_replenish: work that will be called when buffers need to be allocated
* @drv - pointer to iwl_drv
* @trans: pointer to the generic transport area
* @irq - the irq number for the device
* @irq_requested: true when the irq has been requested
* @scd_base_addr: scheduler sram base address in SRAM
* @scd_bc_tbls: pointer to the byte count table of the scheduler
* @kw: keep warm address
@ -234,6 +232,7 @@ struct iwl_txq {
* @status - transport specific status flags
* @cmd_queue - command queue number
* @rx_buf_size_8k: 8 kB RX buffer size
* @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes)
* @rx_page_order: page order for receive buffer size
* @wd_timeout: queue watchdog timeout (jiffies)
*/
@ -249,11 +248,9 @@ struct iwl_trans_pcie {
int ict_index;
u32 inta;
bool use_ict;
bool irq_requested;
struct tasklet_struct irq_tasklet;
struct isr_statistics isr_stats;
unsigned int irq;
spinlock_t irq_lock;
u32 inta_mask;
u32 scd_base_addr;
@ -279,6 +276,7 @@ struct iwl_trans_pcie {
u8 no_reclaim_cmds[MAX_NO_RECLAIM_CMDS];
bool rx_buf_size_8k;
bool bc_table_dword;
u32 rx_page_order;
const char **command_names;
@ -359,6 +357,8 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
struct iwl_rx_cmd_buffer *rxb, int handler_status);
void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
struct sk_buff_head *skbs);
void iwl_trans_pcie_tx_reset(struct iwl_trans *trans);
/*****************************************************
* Error handling
******************************************************/

View file

@ -436,7 +436,7 @@ static int iwl_pcie_rx_alloc(struct iwl_trans *trans)
err_rb_stts:
dma_free_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
rxq->bd, rxq->bd_dma);
memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
rxq->bd_dma = 0;
rxq->bd = NULL;
err_bd:
return -ENOMEM;
@ -455,6 +455,10 @@ static void iwl_pcie_rx_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq)
/* Stop Rx DMA */
iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
/* reset and flush pointers */
iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_RBDCB_WPTR, 0);
iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_FLUSH_RB_REQ, 0);
iwl_write_direct32(trans, FH_RSCSR_CHNL0_RDPTR, 0);
/* Reset driver's Rx queue write index */
iwl_write_direct32(trans, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
@ -491,7 +495,6 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_rxq *rxq = &trans_pcie->rxq;
int i, err;
unsigned long flags;
@ -518,6 +521,7 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
rxq->read = rxq->write = 0;
rxq->write_actual = 0;
rxq->free_count = 0;
memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts));
spin_unlock_irqrestore(&rxq->lock, flags);
iwl_pcie_rx_replenish(trans);
@ -545,13 +549,15 @@ void iwl_pcie_rx_free(struct iwl_trans *trans)
return;
}
cancel_work_sync(&trans_pcie->rx_replenish);
spin_lock_irqsave(&rxq->lock, flags);
iwl_pcie_rxq_free_rbs(trans);
spin_unlock_irqrestore(&rxq->lock, flags);
dma_free_coherent(trans->dev, sizeof(__le32) * RX_QUEUE_SIZE,
rxq->bd, rxq->bd_dma);
memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
rxq->bd_dma = 0;
rxq->bd = NULL;
if (rxq->rb_stts)
@ -560,7 +566,7 @@ void iwl_pcie_rx_free(struct iwl_trans *trans)
rxq->rb_stts, rxq->rb_stts_dma);
else
IWL_DEBUG_INFO(trans, "Free rxq->rb_stts which is NULL\n");
memset(&rxq->rb_stts_dma, 0, sizeof(rxq->rb_stts_dma));
rxq->rb_stts_dma = 0;
rxq->rb_stts = NULL;
}

View file

@ -75,21 +75,16 @@
#include "iwl-agn-hw.h"
#include "internal.h"
static void iwl_pcie_set_pwr_vmain(struct iwl_trans *trans)
static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux)
{
/*
* (for documentation purposes)
* to set power to V_AUX, do:
if (pci_pme_capable(priv->pci_dev, PCI_D3cold))
iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG,
APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
~APMG_PS_CTRL_MSK_PWR_SRC);
*/
iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG,
APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
~APMG_PS_CTRL_MSK_PWR_SRC);
if (vaux && pci_pme_capable(to_pci_dev(trans->dev), PCI_D3cold))
iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG,
APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
~APMG_PS_CTRL_MSK_PWR_SRC);
else
iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG,
APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
~APMG_PS_CTRL_MSK_PWR_SRC);
}
/* PCI registers */
@ -259,7 +254,7 @@ static int iwl_pcie_nic_init(struct iwl_trans *trans)
spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
iwl_pcie_set_pwr_vmain(trans);
iwl_pcie_set_pwr(trans, false);
iwl_op_mode_nic_config(trans->op_mode);
@ -435,7 +430,7 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
}
static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
const struct fw_img *fw)
const struct fw_img *fw, bool run_in_rfkill)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
int ret;
@ -454,7 +449,7 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
/* If platform's RF_KILL switch is NOT set to KILL */
hw_rfkill = iwl_is_rfkill_set(trans);
iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
if (hw_rfkill)
if (hw_rfkill && !run_in_rfkill)
return -ERFKILL;
iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
@ -534,12 +529,6 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
iwl_enable_rfkill_int(trans);
/* wait to make sure we flush pending tasklet*/
synchronize_irq(trans_pcie->irq);
tasklet_kill(&trans_pcie->irq_tasklet);
cancel_work_sync(&trans_pcie->rx_replenish);
/* stop and reset the on-board processor */
iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
@ -551,46 +540,87 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
clear_bit(STATUS_RFKILL, &trans_pcie->status);
}
static void iwl_trans_pcie_wowlan_suspend(struct iwl_trans *trans)
static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans)
{
/* let the ucode operate on its own */
iwl_write32(trans, CSR_UCODE_DRV_GP1_SET,
CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
iwl_disable_interrupts(trans);
iwl_pcie_disable_ict(trans);
iwl_clear_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
iwl_clear_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
/*
* reset TX queues -- some of their registers reset during S3
* so if we don't reset everything here the D3 image would try
* to execute some invalid memory upon resume
*/
iwl_trans_pcie_tx_reset(trans);
iwl_pcie_set_pwr(trans, true);
}
static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
enum iwl_d3_status *status)
{
u32 val;
int ret;
iwl_pcie_set_pwr(trans, false);
val = iwl_read32(trans, CSR_RESET);
if (val & CSR_RESET_REG_FLAG_NEVO_RESET) {
*status = IWL_D3_STATUS_RESET;
return 0;
}
/*
* Also enables interrupts - none will happen as the device doesn't
* know we're waking it up, only when the opmode actually tells it
* after this call.
*/
iwl_pcie_reset_ict(trans);
iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
25000);
if (ret) {
IWL_ERR(trans, "Failed to resume the device (mac ready)\n");
return ret;
}
iwl_trans_pcie_tx_reset(trans);
ret = iwl_pcie_rx_init(trans);
if (ret) {
IWL_ERR(trans, "Failed to resume the device (RX reset)\n");
return ret;
}
iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR,
CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
*status = IWL_D3_STATUS_ALIVE;
return 0;
}
static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
int err;
bool hw_rfkill;
trans_pcie->inta_mask = CSR_INI_SET_MASK;
if (!trans_pcie->irq_requested) {
tasklet_init(&trans_pcie->irq_tasklet, (void (*)(unsigned long))
iwl_pcie_tasklet, (unsigned long)trans);
iwl_pcie_alloc_ict(trans);
err = request_irq(trans_pcie->irq, iwl_pcie_isr_ict,
IRQF_SHARED, DRV_NAME, trans);
if (err) {
IWL_ERR(trans, "Error allocating IRQ %d\n",
trans_pcie->irq);
goto error;
}
trans_pcie->irq_requested = true;
}
int err;
err = iwl_pcie_prepare_card_hw(trans);
if (err) {
IWL_ERR(trans, "Error while preparing HW: %d\n", err);
goto err_free_irq;
return err;
}
iwl_pcie_apm_init(trans);
@ -601,15 +631,7 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
hw_rfkill = iwl_is_rfkill_set(trans);
iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
return err;
err_free_irq:
trans_pcie->irq_requested = false;
free_irq(trans_pcie->irq, trans);
error:
iwl_pcie_free_ict(trans);
tasklet_kill(&trans_pcie->irq_tasklet);
return err;
return 0;
}
static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans,
@ -703,19 +725,21 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans,
msecs_to_jiffies(trans_cfg->queue_watchdog_timeout);
trans_pcie->command_names = trans_cfg->command_names;
trans_pcie->bc_table_dword = trans_cfg->bc_table_dword;
}
void iwl_trans_pcie_free(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
synchronize_irq(trans_pcie->pci_dev->irq);
tasklet_kill(&trans_pcie->irq_tasklet);
iwl_pcie_tx_free(trans);
iwl_pcie_rx_free(trans);
if (trans_pcie->irq_requested == true) {
free_irq(trans_pcie->irq, trans);
iwl_pcie_free_ict(trans);
}
free_irq(trans_pcie->pci_dev->irq, trans);
iwl_pcie_free_ict(trans);
pci_disable_msi(trans_pcie->pci_dev);
iounmap(trans_pcie->hw_base);
@ -751,13 +775,112 @@ static int iwl_trans_pcie_resume(struct iwl_trans *trans)
hw_rfkill = iwl_is_rfkill_set(trans);
iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
if (!hw_rfkill)
iwl_enable_interrupts(trans);
return 0;
}
#endif /* CONFIG_PM_SLEEP */
static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent)
{
int ret;
lockdep_assert_held(&trans->reg_lock);
/* this bit wakes up the NIC */
__iwl_set_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
/*
* These bits say the device is running, and should keep running for
* at least a short while (at least as long as MAC_ACCESS_REQ stays 1),
* but they do not indicate that embedded SRAM is restored yet;
* 3945 and 4965 have volatile SRAM, and must save/restore contents
* to/from host DRAM when sleeping/waking for power-saving.
* Each direction takes approximately 1/4 millisecond; with this
* overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a
* series of register accesses are expected (e.g. reading Event Log),
* to keep device from sleeping.
*
* CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that
* SRAM is okay/restored. We don't check that here because this call
* is just for hardware register access; but GP1 MAC_SLEEP check is a
* good idea before accessing 3945/4965 SRAM (e.g. reading Event Log).
*
* 5000 series and later (including 1000 series) have non-volatile SRAM,
* and do not save/restore SRAM when power cycling.
*/
ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
(CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000);
if (unlikely(ret < 0)) {
iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI);
if (!silent) {
u32 val = iwl_read32(trans, CSR_GP_CNTRL);
WARN_ONCE(1,
"Timeout waiting for hardware access (CSR_GP_CNTRL 0x%08x)\n",
val);
return false;
}
}
return true;
}
static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans)
{
lockdep_assert_held(&trans->reg_lock);
__iwl_clear_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
/*
* Above we read the CSR_GP_CNTRL register, which will flush
* any previous writes, but we need the write that clears the
* MAC_ACCESS_REQ bit to be performed before any other writes
* scheduled on different CPUs (after we drop reg_lock).
*/
mmiowb();
}
static int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr,
void *buf, int dwords)
{
unsigned long flags;
int offs, ret = 0;
u32 *vals = buf;
spin_lock_irqsave(&trans->reg_lock, flags);
if (iwl_trans_grab_nic_access(trans, false)) {
iwl_write32(trans, HBUS_TARG_MEM_RADDR, addr);
for (offs = 0; offs < dwords; offs++)
vals[offs] = iwl_read32(trans, HBUS_TARG_MEM_RDAT);
iwl_trans_release_nic_access(trans);
} else {
ret = -EBUSY;
}
spin_unlock_irqrestore(&trans->reg_lock, flags);
return ret;
}
static int iwl_trans_pcie_write_mem(struct iwl_trans *trans, u32 addr,
void *buf, int dwords)
{
unsigned long flags;
int offs, ret = 0;
u32 *vals = buf;
spin_lock_irqsave(&trans->reg_lock, flags);
if (iwl_trans_grab_nic_access(trans, false)) {
iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr);
for (offs = 0; offs < dwords; offs++)
iwl_write32(trans, HBUS_TARG_MEM_WDAT,
vals ? vals[offs] : 0);
iwl_trans_release_nic_access(trans);
} else {
ret = -EBUSY;
}
spin_unlock_irqrestore(&trans->reg_lock, flags);
return ret;
}
#define IWL_FLUSH_WAIT_MS 2000
static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans)
@ -767,6 +890,8 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans)
struct iwl_queue *q;
int cnt;
unsigned long now = jiffies;
u32 scd_sram_addr;
u8 buf[16];
int ret = 0;
/* waiting for all the tx frames complete might take a while */
@ -780,11 +905,50 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans)
msleep(1);
if (q->read_ptr != q->write_ptr) {
IWL_ERR(trans, "fail to flush all tx fifo queues\n");
IWL_ERR(trans,
"fail to flush all tx fifo queues Q %d\n", cnt);
ret = -ETIMEDOUT;
break;
}
}
if (!ret)
return 0;
IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n",
txq->q.read_ptr, txq->q.write_ptr);
scd_sram_addr = trans_pcie->scd_base_addr +
SCD_TX_STTS_QUEUE_OFFSET(txq->q.id);
iwl_trans_read_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf));
iwl_print_hex_error(trans, buf, sizeof(buf));
for (cnt = 0; cnt < FH_TCSR_CHNL_NUM; cnt++)
IWL_ERR(trans, "FH TRBs(%d) = 0x%08x\n", cnt,
iwl_read_direct32(trans, FH_TX_TRB_REG(cnt)));
for (cnt = 0; cnt < trans->cfg->base_params->num_of_queues; cnt++) {
u32 status = iwl_read_prph(trans, SCD_QUEUE_STATUS_BITS(cnt));
u8 fifo = (status >> SCD_QUEUE_STTS_REG_POS_TXF) & 0x7;
bool active = !!(status & BIT(SCD_QUEUE_STTS_REG_POS_ACTIVE));
u32 tbl_dw =
iwl_trans_read_mem32(trans, trans_pcie->scd_base_addr +
SCD_TRANS_TBL_OFFSET_QUEUE(cnt));
if (cnt & 0x1)
tbl_dw = (tbl_dw & 0xFFFF0000) >> 16;
else
tbl_dw = tbl_dw & 0x0000FFFF;
IWL_ERR(trans,
"Q %d is %sactive and mapped to fifo %d ra_tid 0x%04x [%d,%d]\n",
cnt, active ? "" : "in", fifo, tbl_dw,
iwl_read_prph(trans,
SCD_QUEUE_RDPTR(cnt)) & (txq->q.n_bd - 1),
iwl_read_prph(trans, SCD_QUEUE_WRPTR(cnt)));
}
return ret;
}
@ -1212,7 +1376,8 @@ static const struct iwl_trans_ops trans_ops_pcie = {
.start_fw = iwl_trans_pcie_start_fw,
.stop_device = iwl_trans_pcie_stop_device,
.wowlan_suspend = iwl_trans_pcie_wowlan_suspend,
.d3_suspend = iwl_trans_pcie_d3_suspend,
.d3_resume = iwl_trans_pcie_d3_resume,
.send_cmd = iwl_trans_pcie_send_hcmd,
@ -1235,8 +1400,12 @@ static const struct iwl_trans_ops trans_ops_pcie = {
.read32 = iwl_trans_pcie_read32,
.read_prph = iwl_trans_pcie_read_prph,
.write_prph = iwl_trans_pcie_write_prph,
.read_mem = iwl_trans_pcie_read_mem,
.write_mem = iwl_trans_pcie_write_mem,
.configure = iwl_trans_pcie_configure,
.set_pmi = iwl_trans_pcie_set_pmi,
.grab_nic_access = iwl_trans_pcie_grab_nic_access,
.release_nic_access = iwl_trans_pcie_release_nic_access
};
struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
@ -1318,7 +1487,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
}
trans->dev = &pdev->dev;
trans_pcie->irq = pdev->irq;
trans_pcie->pci_dev = pdev;
trans->hw_rev = iwl_read32(trans, CSR_HW_REV);
trans->hw_id = (pdev->device << 16) + pdev->subsystem_device;
@ -1344,8 +1512,27 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
if (!trans->dev_cmd_pool)
goto out_pci_disable_msi;
trans_pcie->inta_mask = CSR_INI_SET_MASK;
tasklet_init(&trans_pcie->irq_tasklet, (void (*)(unsigned long))
iwl_pcie_tasklet, (unsigned long)trans);
if (iwl_pcie_alloc_ict(trans))
goto out_free_cmd_pool;
err = request_irq(pdev->irq, iwl_pcie_isr_ict,
IRQF_SHARED, DRV_NAME, trans);
if (err) {
IWL_ERR(trans, "Error allocating IRQ %d\n", pdev->irq);
goto out_free_ict;
}
return trans;
out_free_ict:
iwl_pcie_free_ict(trans);
out_free_cmd_pool:
kmem_cache_destroy(trans->dev_cmd_pool);
out_pci_disable_msi:
pci_disable_msi(pdev);
out_pci_release_regions:

View file

@ -160,7 +160,7 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data)
IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n",
txq->q.read_ptr, txq->q.write_ptr);
iwl_read_targ_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf));
iwl_trans_read_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf));
iwl_print_hex_error(trans, buf, sizeof(buf));
@ -173,9 +173,9 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data)
u8 fifo = (status >> SCD_QUEUE_STTS_REG_POS_TXF) & 0x7;
bool active = !!(status & BIT(SCD_QUEUE_STTS_REG_POS_ACTIVE));
u32 tbl_dw =
iwl_read_targ_mem(trans,
trans_pcie->scd_base_addr +
SCD_TRANS_TBL_OFFSET_QUEUE(i));
iwl_trans_read_mem32(trans,
trans_pcie->scd_base_addr +
SCD_TRANS_TBL_OFFSET_QUEUE(i));
if (i & 0x1)
tbl_dw = (tbl_dw & 0xFFFF0000) >> 16;
@ -237,7 +237,10 @@ static void iwl_pcie_txq_update_byte_cnt_tbl(struct iwl_trans *trans,
break;
}
bc_ent = cpu_to_le16((len & 0xFFF) | (sta_id << 12));
if (trans_pcie->bc_table_dword)
len = DIV_ROUND_UP(len, 4);
bc_ent = cpu_to_le16(len | (sta_id << 12));
scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent;
@ -306,6 +309,9 @@ void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_txq *txq)
return;
}
IWL_DEBUG_TX(trans, "Q:%d WR: 0x%x\n", txq_id,
txq->q.write_ptr);
iwl_write_direct32(trans, HBUS_TARG_WRPTR,
txq->q.write_ptr | (txq_id << 8));
@ -612,7 +618,7 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id)
if (txq->q.n_bd) {
dma_free_coherent(dev, sizeof(struct iwl_tfd) *
txq->q.n_bd, txq->tfds, txq->q.dma_addr);
memset(&txq->q.dma_addr, 0, sizeof(txq->q.dma_addr));
txq->q.dma_addr = 0;
}
kfree(txq->entries);
@ -638,9 +644,11 @@ static void iwl_pcie_txq_set_sched(struct iwl_trans *trans, u32 mask)
void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
u32 a;
int nq = trans->cfg->base_params->num_of_queues;
int chan;
u32 reg_val;
int clear_dwords = (SCD_TRANS_TBL_OFFSET_QUEUE(nq) -
SCD_CONTEXT_MEM_LOWER_BOUND) / sizeof(u32);
/* make sure all queue are not stopped/used */
memset(trans_pcie->queue_stopped, 0, sizeof(trans_pcie->queue_stopped));
@ -652,20 +660,10 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr)
WARN_ON(scd_base_addr != 0 &&
scd_base_addr != trans_pcie->scd_base_addr);
a = trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_LOWER_BOUND;
/* reset conext data memory */
for (; a < trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_UPPER_BOUND;
a += 4)
iwl_write_targ_mem(trans, a, 0);
/* reset tx status memory */
for (; a < trans_pcie->scd_base_addr + SCD_TX_STTS_MEM_UPPER_BOUND;
a += 4)
iwl_write_targ_mem(trans, a, 0);
for (; a < trans_pcie->scd_base_addr +
SCD_TRANS_TBL_OFFSET_QUEUE(
trans->cfg->base_params->num_of_queues);
a += 4)
iwl_write_targ_mem(trans, a, 0);
/* reset context data, TX status and translation data */
iwl_trans_write_mem(trans, trans_pcie->scd_base_addr +
SCD_CONTEXT_MEM_LOWER_BOUND,
NULL, clear_dwords);
iwl_write_prph(trans, SCD_DRAM_BASE_ADDR,
trans_pcie->scd_bc_tbls.dma >> 10);
@ -697,6 +695,29 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr)
APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
}
void iwl_trans_pcie_tx_reset(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
int txq_id;
for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues;
txq_id++) {
struct iwl_txq *txq = &trans_pcie->txq[txq_id];
iwl_write_direct32(trans, FH_MEM_CBBC_QUEUE(txq_id),
txq->q.dma_addr >> 8);
iwl_pcie_txq_unmap(trans, txq_id);
txq->q.read_ptr = 0;
txq->q.write_ptr = 0;
}
/* Tell NIC where to find the "keep warm" buffer */
iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG,
trans_pcie->kw.dma >> 4);
iwl_pcie_tx_start(trans, trans_pcie->scd_base_addr);
}
/*
* iwl_pcie_tx_stop - Stop all Tx DMA channels
*/
@ -1002,14 +1023,14 @@ static int iwl_pcie_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid,
tbl_dw_addr = trans_pcie->scd_base_addr +
SCD_TRANS_TBL_OFFSET_QUEUE(txq_id);
tbl_dw = iwl_read_targ_mem(trans, tbl_dw_addr);
tbl_dw = iwl_trans_read_mem32(trans, tbl_dw_addr);
if (txq_id & 0x1)
tbl_dw = (scd_q2ratid << 16) | (tbl_dw & 0x0000FFFF);
else
tbl_dw = scd_q2ratid | (tbl_dw & 0xFFFF0000);
iwl_write_targ_mem(trans, tbl_dw_addr, tbl_dw);
iwl_trans_write_mem32(trans, tbl_dw_addr, tbl_dw);
return 0;
}
@ -1068,9 +1089,9 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo,
iwl_write_prph(trans, SCD_QUEUE_RDPTR(txq_id), ssn);
/* Set up Tx window size and frame limit for this queue */
iwl_write_targ_mem(trans, trans_pcie->scd_base_addr +
iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr +
SCD_CONTEXT_QUEUE_OFFSET(txq_id), 0);
iwl_write_targ_mem(trans, trans_pcie->scd_base_addr +
iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr +
SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32),
((frame_limit << SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
@ -1101,8 +1122,8 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id)
iwl_pcie_txq_set_inactive(trans, txq_id);
_iwl_write_targ_mem_dwords(trans, stts_addr,
zero_val, ARRAY_SIZE(zero_val));
iwl_trans_write_mem(trans, stts_addr, (void *)zero_val,
ARRAY_SIZE(zero_val));
iwl_pcie_txq_unmap(trans, txq_id);
@ -1642,10 +1663,6 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys);
IWL_DEBUG_TX(trans, "sequence nr = 0X%x\n",
le16_to_cpu(dev_cmd->hdr.sequence));
IWL_DEBUG_TX(trans, "tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags));
/* Set up entry for this TFD in Tx byte-count array */
iwl_pcie_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len));

View file

@ -2132,6 +2132,21 @@ static void lbs_cfg_set_regulatory_hint(struct lbs_private *priv)
lbs_deb_leave(LBS_DEB_CFG80211);
}
static void lbs_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
{
struct lbs_private *priv = wiphy_priv(wiphy);
lbs_deb_enter_args(LBS_DEB_CFG80211, "cfg80211 regulatory domain "
"callback for domain %c%c\n", request->alpha2[0],
request->alpha2[1]);
memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2));
if (lbs_iface_active(priv))
lbs_set_11d_domain_info(priv);
lbs_deb_leave(LBS_DEB_CFG80211);
}
/*
* This function get's called after lbs_setup_firmware() determined the
@ -2184,24 +2199,6 @@ int lbs_cfg_register(struct lbs_private *priv)
return ret;
}
int lbs_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
{
struct lbs_private *priv = wiphy_priv(wiphy);
int ret = 0;
lbs_deb_enter_args(LBS_DEB_CFG80211, "cfg80211 regulatory domain "
"callback for domain %c%c\n", request->alpha2[0],
request->alpha2[1]);
memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2));
if (lbs_iface_active(priv))
ret = lbs_set_11d_domain_info(priv);
lbs_deb_leave(LBS_DEB_CFG80211);
return ret;
}
void lbs_scan_deinit(struct lbs_private *priv)
{
lbs_deb_enter(LBS_DEB_CFG80211);

View file

@ -10,9 +10,6 @@ struct wireless_dev *lbs_cfg_alloc(struct device *dev);
int lbs_cfg_register(struct lbs_private *priv);
void lbs_cfg_free(struct lbs_private *priv);
int lbs_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request);
void lbs_send_disconnect_notification(struct lbs_private *priv);
void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event);

View file

@ -48,6 +48,10 @@ static int channels = 1;
module_param(channels, int, 0444);
MODULE_PARM_DESC(channels, "Number of concurrent channels");
static bool paged_rx = false;
module_param(paged_rx, bool, 0644);
MODULE_PARM_DESC(paged_rx, "Use paged SKBs for RX instead of linear ones");
/**
* enum hwsim_regtest - the type of regulatory tests we offer
*
@ -333,11 +337,11 @@ struct mac80211_hwsim_data {
int scan_chan_idx;
struct ieee80211_channel *channel;
unsigned long beacon_int; /* in jiffies unit */
u64 beacon_int /* beacon interval in us */;
unsigned int rx_filter;
bool started, idle, scanning;
struct mutex mutex;
struct timer_list beacon_timer;
struct tasklet_hrtimer beacon_timer;
enum ps_mode {
PS_DISABLED, PS_ENABLED, PS_AUTO_POLL, PS_MANUAL_POLL
} ps;
@ -357,7 +361,10 @@ struct mac80211_hwsim_data {
int power_level;
/* difference between this hw's clock and the real clock, in usecs */
u64 tsf_offset;
s64 tsf_offset;
s64 bcn_delta;
/* absolute beacon transmission time. Used to cover up "tx" delay. */
u64 abs_bcn_ts;
};
@ -405,15 +412,19 @@ static netdev_tx_t hwsim_mon_xmit(struct sk_buff *skb,
return NETDEV_TX_OK;
}
static inline u64 mac80211_hwsim_get_tsf_raw(void)
{
return ktime_to_us(ktime_get_real());
}
static __le64 __mac80211_hwsim_get_tsf(struct mac80211_hwsim_data *data)
{
struct timeval tv = ktime_to_timeval(ktime_get_real());
u64 now = tv.tv_sec * USEC_PER_SEC + tv.tv_usec;
u64 now = mac80211_hwsim_get_tsf_raw();
return cpu_to_le64(now + data->tsf_offset);
}
static u64 mac80211_hwsim_get_tsf(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
struct ieee80211_vif *vif)
{
struct mac80211_hwsim_data *data = hw->priv;
return le64_to_cpu(__mac80211_hwsim_get_tsf(data));
@ -423,9 +434,13 @@ static void mac80211_hwsim_set_tsf(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u64 tsf)
{
struct mac80211_hwsim_data *data = hw->priv;
struct timeval tv = ktime_to_timeval(ktime_get_real());
u64 now = tv.tv_sec * USEC_PER_SEC + tv.tv_usec;
data->tsf_offset = tsf - now;
u64 now = mac80211_hwsim_get_tsf(hw, vif);
u32 bcn_int = data->beacon_int;
s64 delta = tsf - now;
data->tsf_offset += delta;
/* adjust after beaconing with new timestamp at old TBTT */
data->bcn_delta = do_div(delta, bcn_int);
}
static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
@ -696,7 +711,7 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_rx_status rx_status;
struct ieee80211_rate *txrate = ieee80211_get_tx_rate(hw, info);
u64 now;
memset(&rx_status, 0, sizeof(rx_status));
rx_status.flag |= RX_FLAG_MACTIME_START;
@ -722,11 +737,23 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
secpath_reset(skb);
nf_reset(skb);
/*
* Get absolute mactime here so all HWs RX at the "same time", and
* absolute TX time for beacon mactime so the timestamp matches.
* Giving beacons a different mactime than non-beacons looks messy, but
* it helps the Toffset be exact and a ~10us mactime discrepancy
* probably doesn't really matter.
*/
if (ieee80211_is_beacon(hdr->frame_control) ||
ieee80211_is_probe_resp(hdr->frame_control))
now = data->abs_bcn_ts;
else
now = mac80211_hwsim_get_tsf_raw();
/* Copy skb to all enabled radios that are on the current frequency */
spin_lock(&hwsim_radio_lock);
list_for_each_entry(data2, &hwsim_radios, list) {
struct sk_buff *nskb;
struct ieee80211_mgmt *mgmt;
struct tx_iter_data tx_iter_data = {
.receive = false,
.channel = chan,
@ -755,24 +782,30 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
* reserve some space for our vendor and the normal
* radiotap header, since we're copying anyway
*/
nskb = skb_copy_expand(skb, 64, 0, GFP_ATOMIC);
if (nskb == NULL)
continue;
if (skb->len < PAGE_SIZE && paged_rx) {
struct page *page = alloc_page(GFP_ATOMIC);
if (!page)
continue;
nskb = dev_alloc_skb(128);
if (!nskb) {
__free_page(page);
continue;
}
memcpy(page_address(page), skb->data, skb->len);
skb_add_rx_frag(nskb, 0, page, 0, skb->len, skb->len);
} else {
nskb = skb_copy(skb, GFP_ATOMIC);
if (!nskb)
continue;
}
if (mac80211_hwsim_addr_match(data2, hdr->addr1))
ack = true;
/* set bcn timestamp relative to receiver mactime */
rx_status.mactime =
le64_to_cpu(__mac80211_hwsim_get_tsf(data2));
mgmt = (struct ieee80211_mgmt *) nskb->data;
if (ieee80211_is_beacon(mgmt->frame_control) ||
ieee80211_is_probe_resp(mgmt->frame_control))
mgmt->u.beacon.timestamp = cpu_to_le64(
rx_status.mactime +
(data->tsf_offset - data2->tsf_offset) +
24 * 8 * 10 / txrate->bitrate);
rx_status.mactime = now + data2->tsf_offset;
#if 0
/*
* Don't enable this code by default as the OUI 00:00:00
@ -896,7 +929,7 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw)
{
struct mac80211_hwsim_data *data = hw->priv;
data->started = false;
del_timer(&data->beacon_timer);
tasklet_hrtimer_cancel(&data->beacon_timer);
wiphy_debug(hw->wiphy, "%s\n", __func__);
}
@ -962,7 +995,11 @@ static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
struct ieee80211_vif *vif)
{
struct ieee80211_hw *hw = arg;
struct mac80211_hwsim_data *data = arg;
struct ieee80211_hw *hw = data->hw;
struct ieee80211_tx_info *info;
struct ieee80211_rate *txrate;
struct ieee80211_mgmt *mgmt;
struct sk_buff *skb;
hwsim_check_magic(vif);
@ -975,26 +1012,48 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
skb = ieee80211_beacon_get(hw, vif);
if (skb == NULL)
return;
info = IEEE80211_SKB_CB(skb);
txrate = ieee80211_get_tx_rate(hw, info);
mgmt = (struct ieee80211_mgmt *) skb->data;
/* fake header transmission time */
data->abs_bcn_ts = mac80211_hwsim_get_tsf_raw();
mgmt->u.beacon.timestamp = cpu_to_le64(data->abs_bcn_ts +
data->tsf_offset +
24 * 8 * 10 / txrate->bitrate);
mac80211_hwsim_tx_frame(hw, skb,
rcu_dereference(vif->chanctx_conf)->def.chan);
}
static void mac80211_hwsim_beacon(unsigned long arg)
static enum hrtimer_restart
mac80211_hwsim_beacon(struct hrtimer *timer)
{
struct ieee80211_hw *hw = (struct ieee80211_hw *) arg;
struct mac80211_hwsim_data *data = hw->priv;
struct mac80211_hwsim_data *data =
container_of(timer, struct mac80211_hwsim_data,
beacon_timer.timer);
struct ieee80211_hw *hw = data->hw;
u64 bcn_int = data->beacon_int;
ktime_t next_bcn;
if (!data->started)
return;
goto out;
ieee80211_iterate_active_interfaces_atomic(
hw, IEEE80211_IFACE_ITER_NORMAL,
mac80211_hwsim_beacon_tx, hw);
mac80211_hwsim_beacon_tx, data);
data->beacon_timer.expires = jiffies + data->beacon_int;
add_timer(&data->beacon_timer);
/* beacon at new TBTT + beacon interval */
if (data->bcn_delta) {
bcn_int -= data->bcn_delta;
data->bcn_delta = 0;
}
next_bcn = ktime_add(hrtimer_get_expires(timer),
ns_to_ktime(bcn_int * 1000));
tasklet_hrtimer_start(&data->beacon_timer, next_bcn, HRTIMER_MODE_ABS);
out:
return HRTIMER_NORESTART;
}
static const char *hwsim_chantypes[] = {
@ -1032,9 +1091,16 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
data->power_level = conf->power_level;
if (!data->started || !data->beacon_int)
del_timer(&data->beacon_timer);
else
mod_timer(&data->beacon_timer, jiffies + data->beacon_int);
tasklet_hrtimer_cancel(&data->beacon_timer);
else if (!hrtimer_is_queued(&data->beacon_timer.timer)) {
u64 tsf = mac80211_hwsim_get_tsf(hw, NULL);
u32 bcn_int = data->beacon_int;
u64 until_tbtt = bcn_int - do_div(tsf, bcn_int);
tasklet_hrtimer_start(&data->beacon_timer,
ns_to_ktime(until_tbtt * 1000),
HRTIMER_MODE_REL);
}
return 0;
}
@ -1084,12 +1150,26 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_BEACON_INT) {
wiphy_debug(hw->wiphy, " BCNINT: %d\n", info->beacon_int);
data->beacon_int = 1024 * info->beacon_int / 1000 * HZ / 1000;
if (WARN_ON(!data->beacon_int))
data->beacon_int = 1;
if (data->started)
mod_timer(&data->beacon_timer,
jiffies + data->beacon_int);
data->beacon_int = info->beacon_int * 1024;
}
if (changed & BSS_CHANGED_BEACON_ENABLED) {
wiphy_debug(hw->wiphy, " BCN EN: %d\n", info->enable_beacon);
if (data->started &&
!hrtimer_is_queued(&data->beacon_timer.timer) &&
info->enable_beacon) {
u64 tsf, until_tbtt;
u32 bcn_int;
if (WARN_ON(!data->beacon_int))
data->beacon_int = 1000 * 1024;
tsf = mac80211_hwsim_get_tsf(hw, vif);
bcn_int = data->beacon_int;
until_tbtt = bcn_int - do_div(tsf, bcn_int);
tasklet_hrtimer_start(&data->beacon_timer,
ns_to_ktime(until_tbtt * 1000),
HRTIMER_MODE_REL);
} else if (!info->enable_beacon)
tasklet_hrtimer_cancel(&data->beacon_timer);
}
if (changed & BSS_CHANGED_ERP_CTS_PROT) {
@ -1292,7 +1372,9 @@ static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw,
case IEEE80211_AMPDU_TX_START:
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
case IEEE80211_AMPDU_TX_STOP:
case IEEE80211_AMPDU_TX_STOP_CONT:
case IEEE80211_AMPDU_TX_STOP_FLUSH:
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
@ -2370,8 +2452,9 @@ static int __init init_mac80211_hwsim(void)
data->debugfs, data,
&hwsim_fops_group);
setup_timer(&data->beacon_timer, mac80211_hwsim_beacon,
(unsigned long) hw);
tasklet_hrtimer_init(&data->beacon_timer,
mac80211_hwsim_beacon,
CLOCK_REALTIME, HRTIMER_MODE_ABS);
list_add_tail(&data->list, &hwsim_radios);
}

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