Merge remote-tracking branch 'wireless-next/master' into HEAD
This commit is contained in:
commit
448cd55c37
195 changed files with 12043 additions and 3515 deletions
|
@ -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
|
||||
------------------------------------------
|
||||
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -1353,6 +1353,14 @@ W: http://wireless.kernel.org/en/users/Drivers/ath9k
|
|||
S: Supported
|
||||
F: drivers/net/wireless/ath/ath9k/
|
||||
|
||||
WILOCITY WIL6210 WIRELESS DRIVER
|
||||
M: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
L: wil6210@qca.qualcomm.com
|
||||
S: Supported
|
||||
W: http://wireless.kernel.org/en/users/Drivers/wil6210
|
||||
F: drivers/net/wireless/ath/wil6210/
|
||||
|
||||
CARL9170 LINUX COMMUNITY WIRELESS DRIVER
|
||||
M: Christian Lamparter <chunkeey@googlemail.com>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -67,8 +67,7 @@ config BCMA_DRIVER_GMAC_CMN
|
|||
|
||||
config BCMA_DRIVER_GPIO
|
||||
bool "BCMA GPIO driver"
|
||||
depends on BCMA
|
||||
select GPIOLIB
|
||||
depends on BCMA && GPIOLIB
|
||||
help
|
||||
Driver to provide access to the GPIO pins of the bcma bus.
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -35,7 +35,7 @@ static struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
|
|||
{ "M25P40", 0x12, 0x10000, 8, },
|
||||
|
||||
{ "M25P16", 0x14, 0x10000, 32, },
|
||||
{ "M25P32", 0x14, 0x10000, 64, },
|
||||
{ "M25P32", 0x15, 0x10000, 64, },
|
||||
{ "M25P64", 0x16, 0x10000, 128, },
|
||||
{ "M25FL128", 0x17, 0x10000, 256, },
|
||||
{ 0 },
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
@ -277,7 +280,7 @@ static u8 __devinit bcma_find_pci_capability(struct bcma_drv_pci *pc,
|
|||
/* 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 */
|
||||
|
@ -427,7 +430,7 @@ void __devinit 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);
|
||||
|
||||
|
@ -489,6 +492,17 @@ void __devinit 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));
|
||||
|
@ -577,7 +591,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;
|
||||
|
@ -596,6 +610,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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -30,5 +30,6 @@ source "drivers/net/wireless/ath/ath9k/Kconfig"
|
|||
source "drivers/net/wireless/ath/carl9170/Kconfig"
|
||||
source "drivers/net/wireless/ath/ath6kl/Kconfig"
|
||||
source "drivers/net/wireless/ath/ar5523/Kconfig"
|
||||
source "drivers/net/wireless/ath/wil6210/Kconfig"
|
||||
|
||||
endif
|
||||
|
|
|
@ -3,6 +3,7 @@ obj-$(CONFIG_ATH9K_HW) += ath9k/
|
|||
obj-$(CONFIG_CARL9170) += carl9170/
|
||||
obj-$(CONFIG_ATH6KL) += ath6kl/
|
||||
obj-$(CONFIG_AR5523) += ar5523/
|
||||
obj-$(CONFIG_WIL6210) += wil6210/
|
||||
|
||||
obj-$(CONFIG_ATH_COMMON) += ath.o
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ config ATH9K_HW
|
|||
tristate
|
||||
config ATH9K_COMMON
|
||||
tristate
|
||||
select ATH_COMMON
|
||||
config ATH9K_DFS_DEBUGFS
|
||||
def_bool y
|
||||
depends on ATH9K_DEBUGFS && ATH9K_DFS_CERTIFIED
|
||||
|
@ -17,7 +18,6 @@ config ATH9K_BTCOEX_SUPPORT
|
|||
config ATH9K
|
||||
tristate "Atheros 802.11n wireless cards support"
|
||||
depends on MAC80211
|
||||
select ATH_COMMON
|
||||
select ATH9K_HW
|
||||
select MAC80211_LEDS
|
||||
select LEDS_CLASS
|
||||
|
@ -56,7 +56,8 @@ config ATH9K_AHB
|
|||
|
||||
config ATH9K_DEBUGFS
|
||||
bool "Atheros ath9k debugging"
|
||||
depends on ATH9K && DEBUG_FS
|
||||
depends on ATH9K
|
||||
select MAC80211_DEBUGFS
|
||||
---help---
|
||||
Say Y, if you need access to ath9k's statistics for
|
||||
interrupts, rate control, etc.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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)
|
||||
|
@ -544,7 +575,7 @@ static void ar9003_rx_gain_table_mode0(struct ath_hw *ah)
|
|||
ar9340Common_rx_gain_table_1p0);
|
||||
else if (AR_SREV_9485_11(ah))
|
||||
INIT_INI_ARRAY(&ah->iniModesRxGain,
|
||||
ar9485Common_wo_xlna_rx_gain_1_1);
|
||||
ar9485_common_rx_gain_1_1);
|
||||
else if (AR_SREV_9550(ah)) {
|
||||
INIT_INI_ARRAY(&ah->iniModesRxGain,
|
||||
ar955x_1p0_common_rx_gain_table);
|
||||
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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},
|
||||
};
|
||||
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/ath9k_platform.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/relay.h>
|
||||
|
||||
#include "ath9k.h"
|
||||
|
||||
|
@ -334,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);
|
||||
|
@ -350,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;
|
||||
|
@ -375,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,
|
||||
|
@ -388,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;
|
||||
|
@ -419,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)
|
||||
|
@ -454,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 =
|
||||
|
@ -469,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 =
|
||||
|
@ -562,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;
|
||||
|
@ -633,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 */
|
||||
|
@ -673,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;
|
||||
}
|
||||
|
||||
|
@ -841,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);
|
||||
|
@ -852,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);
|
||||
|
||||
|
@ -878,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);
|
||||
|
@ -898,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;
|
||||
}
|
||||
|
||||
|
@ -920,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++)
|
||||
|
@ -937,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)
|
||||
|
@ -954,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 */
|
||||
/************************/
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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, ¶m);
|
||||
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) {
|
||||
|
@ -1731,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);
|
||||
|
@ -1835,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:
|
||||
|
@ -2240,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,
|
||||
|
@ -2286,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,
|
||||
};
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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))
|
||||
|
@ -336,25 +354,24 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
|
|||
if (SUPP(CARL9170FW_WLANTX_CAB)) {
|
||||
if_comb_types |=
|
||||
BIT(NL80211_IFTYPE_AP) |
|
||||
BIT(NL80211_IFTYPE_MESH_POINT) |
|
||||
BIT(NL80211_IFTYPE_P2P_GO);
|
||||
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
if_comb_types |=
|
||||
BIT(NL80211_IFTYPE_MESH_POINT);
|
||||
#endif /* CONFIG_MAC80211_MESH */
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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]);
|
||||
|
@ -1807,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:
|
||||
|
|
|
@ -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++) {
|
||||
/*
|
||||
|
|
|
@ -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 */
|
||||
|
|
29
drivers/net/wireless/ath/wil6210/Kconfig
Normal file
29
drivers/net/wireless/ath/wil6210/Kconfig
Normal file
|
@ -0,0 +1,29 @@
|
|||
config WIL6210
|
||||
tristate "Wilocity 60g WiFi card wil6210 support"
|
||||
depends on CFG80211
|
||||
depends on PCI
|
||||
default n
|
||||
---help---
|
||||
This module adds support for wireless adapter based on
|
||||
wil6210 chip by Wilocity. It supports operation on the
|
||||
60 GHz band, covered by the IEEE802.11ad standard.
|
||||
|
||||
http://wireless.kernel.org/en/users/Drivers/wil6210
|
||||
|
||||
If you choose to build it as a module, it will be called
|
||||
wil6210
|
||||
|
||||
config WIL6210_ISR_COR
|
||||
bool "Use Clear-On-Read mode for ISR registers for wil6210"
|
||||
depends on WIL6210
|
||||
default y
|
||||
---help---
|
||||
ISR registers on wil6210 chip may operate in either
|
||||
COR (Clear-On-Read) or W1C (Write-1-to-Clear) mode.
|
||||
For production code, use COR (say y); is default since
|
||||
it saves extra target transaction;
|
||||
For ISR debug, use W1C (say n); is allows to monitor ISR
|
||||
registers with debugfs. If COR were used, ISR would
|
||||
self-clear when accessed for debug purposes, it makes
|
||||
such monitoring impossible.
|
||||
Say y unless you debug interrupts
|
13
drivers/net/wireless/ath/wil6210/Makefile
Normal file
13
drivers/net/wireless/ath/wil6210/Makefile
Normal file
|
@ -0,0 +1,13 @@
|
|||
obj-$(CONFIG_WIL6210) += wil6210.o
|
||||
|
||||
wil6210-objs := main.o
|
||||
wil6210-objs += netdev.o
|
||||
wil6210-objs += cfg80211.o
|
||||
wil6210-objs += pcie_bus.o
|
||||
wil6210-objs += debugfs.o
|
||||
wil6210-objs += wmi.o
|
||||
wil6210-objs += interrupt.o
|
||||
wil6210-objs += txrx.o
|
||||
|
||||
subdir-ccflags-y += -Werror
|
||||
subdir-ccflags-y += -D__CHECK_ENDIAN__
|
573
drivers/net/wireless/ath/wil6210/cfg80211.c
Normal file
573
drivers/net/wireless/ath/wil6210/cfg80211.c
Normal file
|
@ -0,0 +1,573 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Qualcomm Atheros, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <linux/ieee80211.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/version.h>
|
||||
#include <net/cfg80211.h>
|
||||
|
||||
#include "wil6210.h"
|
||||
#include "wmi.h"
|
||||
|
||||
#define CHAN60G(_channel, _flags) { \
|
||||
.band = IEEE80211_BAND_60GHZ, \
|
||||
.center_freq = 56160 + (2160 * (_channel)), \
|
||||
.hw_value = (_channel), \
|
||||
.flags = (_flags), \
|
||||
.max_antenna_gain = 0, \
|
||||
.max_power = 40, \
|
||||
}
|
||||
|
||||
static struct ieee80211_channel wil_60ghz_channels[] = {
|
||||
CHAN60G(1, 0),
|
||||
CHAN60G(2, 0),
|
||||
CHAN60G(3, 0),
|
||||
/* channel 4 not supported yet */
|
||||
};
|
||||
|
||||
static struct ieee80211_supported_band wil_band_60ghz = {
|
||||
.channels = wil_60ghz_channels,
|
||||
.n_channels = ARRAY_SIZE(wil_60ghz_channels),
|
||||
.ht_cap = {
|
||||
.ht_supported = true,
|
||||
.cap = 0, /* TODO */
|
||||
.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, /* TODO */
|
||||
.ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, /* TODO */
|
||||
.mcs = {
|
||||
/* MCS 1..12 - SC PHY */
|
||||
.rx_mask = {0xfe, 0x1f}, /* 1..12 */
|
||||
.tx_params = IEEE80211_HT_MCS_TX_DEFINED, /* TODO */
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const struct ieee80211_txrx_stypes
|
||||
wil_mgmt_stypes[NUM_NL80211_IFTYPES] = {
|
||||
[NL80211_IFTYPE_STATION] = {
|
||||
.tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
|
||||
BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
|
||||
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
|
||||
BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
|
||||
},
|
||||
[NL80211_IFTYPE_AP] = {
|
||||
.tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
|
||||
BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
|
||||
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
|
||||
BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
|
||||
},
|
||||
[NL80211_IFTYPE_P2P_CLIENT] = {
|
||||
.tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
|
||||
BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
|
||||
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
|
||||
BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
|
||||
},
|
||||
[NL80211_IFTYPE_P2P_GO] = {
|
||||
.tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
|
||||
BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
|
||||
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
|
||||
BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
|
||||
},
|
||||
};
|
||||
|
||||
static const u32 wil_cipher_suites[] = {
|
||||
WLAN_CIPHER_SUITE_GCMP,
|
||||
};
|
||||
|
||||
int wil_iftype_nl2wmi(enum nl80211_iftype type)
|
||||
{
|
||||
static const struct {
|
||||
enum nl80211_iftype nl;
|
||||
enum wmi_network_type wmi;
|
||||
} __nl2wmi[] = {
|
||||
{NL80211_IFTYPE_ADHOC, WMI_NETTYPE_ADHOC},
|
||||
{NL80211_IFTYPE_STATION, WMI_NETTYPE_INFRA},
|
||||
{NL80211_IFTYPE_AP, WMI_NETTYPE_AP},
|
||||
{NL80211_IFTYPE_P2P_CLIENT, WMI_NETTYPE_P2P},
|
||||
{NL80211_IFTYPE_P2P_GO, WMI_NETTYPE_P2P},
|
||||
{NL80211_IFTYPE_MONITOR, WMI_NETTYPE_ADHOC}, /* FIXME */
|
||||
};
|
||||
uint i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(__nl2wmi); i++) {
|
||||
if (__nl2wmi[i].nl == type)
|
||||
return __nl2wmi[i].wmi;
|
||||
}
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int wil_cfg80211_get_station(struct wiphy *wiphy,
|
||||
struct net_device *ndev,
|
||||
u8 *mac, struct station_info *sinfo)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
int rc;
|
||||
struct wmi_notify_req_cmd cmd = {
|
||||
.cid = 0,
|
||||
.interval_usec = 0,
|
||||
};
|
||||
|
||||
if (memcmp(mac, wil->dst_addr[0], ETH_ALEN))
|
||||
return -ENOENT;
|
||||
|
||||
/* WMI_NOTIFY_REQ_DONE_EVENTID handler fills wil->stats.bf_mcs */
|
||||
rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd),
|
||||
WMI_NOTIFY_REQ_DONE_EVENTID, NULL, 0, 20);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
sinfo->generation = wil->sinfo_gen;
|
||||
|
||||
sinfo->filled |= STATION_INFO_TX_BITRATE;
|
||||
sinfo->txrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
|
||||
sinfo->txrate.mcs = wil->stats.bf_mcs;
|
||||
sinfo->filled |= STATION_INFO_RX_BITRATE;
|
||||
sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
|
||||
sinfo->rxrate.mcs = wil->stats.last_mcs_rx;
|
||||
|
||||
if (test_bit(wil_status_fwconnected, &wil->status)) {
|
||||
sinfo->filled |= STATION_INFO_SIGNAL;
|
||||
sinfo->signal = 12; /* TODO: provide real value */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil_cfg80211_change_iface(struct wiphy *wiphy,
|
||||
struct net_device *ndev,
|
||||
enum nl80211_iftype type, u32 *flags,
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
struct wireless_dev *wdev = wil->wdev;
|
||||
|
||||
switch (type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
break;
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
if (flags)
|
||||
wil->monitor_flags = *flags;
|
||||
else
|
||||
wil->monitor_flags = 0;
|
||||
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
wdev->iftype = type;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil_cfg80211_scan(struct wiphy *wiphy,
|
||||
struct cfg80211_scan_request *request)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
struct wireless_dev *wdev = wil->wdev;
|
||||
struct {
|
||||
struct wmi_start_scan_cmd cmd;
|
||||
u16 chnl[4];
|
||||
} __packed cmd;
|
||||
uint i, n;
|
||||
|
||||
if (wil->scan_request) {
|
||||
wil_err(wil, "Already scanning\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/* check we are client side */
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
}
|
||||
|
||||
/* FW don't support scan after connection attempt */
|
||||
if (test_bit(wil_status_dontscan, &wil->status)) {
|
||||
wil_err(wil, "Scan after connect attempt not supported\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
wil->scan_request = request;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.cmd.num_channels = 0;
|
||||
n = min(request->n_channels, 4U);
|
||||
for (i = 0; i < n; i++) {
|
||||
int ch = request->channels[i]->hw_value;
|
||||
if (ch == 0) {
|
||||
wil_err(wil,
|
||||
"Scan requested for unknown frequency %dMhz\n",
|
||||
request->channels[i]->center_freq);
|
||||
continue;
|
||||
}
|
||||
/* 0-based channel indexes */
|
||||
cmd.cmd.channel_list[cmd.cmd.num_channels++].channel = ch - 1;
|
||||
wil_dbg(wil, "Scan for ch %d : %d MHz\n", ch,
|
||||
request->channels[i]->center_freq);
|
||||
}
|
||||
|
||||
return wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) +
|
||||
cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0]));
|
||||
}
|
||||
|
||||
static int wil_cfg80211_connect(struct wiphy *wiphy,
|
||||
struct net_device *ndev,
|
||||
struct cfg80211_connect_params *sme)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
struct cfg80211_bss *bss;
|
||||
struct wmi_connect_cmd conn;
|
||||
const u8 *ssid_eid;
|
||||
const u8 *rsn_eid;
|
||||
int ch;
|
||||
int rc = 0;
|
||||
|
||||
bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
|
||||
sme->ssid, sme->ssid_len,
|
||||
WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
|
||||
if (!bss) {
|
||||
wil_err(wil, "Unable to find BSS\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ssid_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SSID);
|
||||
if (!ssid_eid) {
|
||||
wil_err(wil, "No SSID\n");
|
||||
rc = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rsn_eid = sme->ie ?
|
||||
cfg80211_find_ie(WLAN_EID_RSN, sme->ie, sme->ie_len) :
|
||||
NULL;
|
||||
if (rsn_eid) {
|
||||
if (sme->ie_len > WMI_MAX_IE_LEN) {
|
||||
rc = -ERANGE;
|
||||
wil_err(wil, "IE too large (%td bytes)\n",
|
||||
sme->ie_len);
|
||||
goto out;
|
||||
}
|
||||
/*
|
||||
* For secure assoc, send:
|
||||
* (1) WMI_DELETE_CIPHER_KEY_CMD
|
||||
* (2) WMI_SET_APPIE_CMD
|
||||
*/
|
||||
rc = wmi_del_cipher_key(wil, 0, bss->bssid);
|
||||
if (rc) {
|
||||
wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD failed\n");
|
||||
goto out;
|
||||
}
|
||||
/* WMI_SET_APPIE_CMD */
|
||||
rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie);
|
||||
if (rc) {
|
||||
wil_err(wil, "WMI_SET_APPIE_CMD failed\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* WMI_CONNECT_CMD */
|
||||
memset(&conn, 0, sizeof(conn));
|
||||
switch (bss->capability & 0x03) {
|
||||
case WLAN_CAPABILITY_DMG_TYPE_AP:
|
||||
conn.network_type = WMI_NETTYPE_INFRA;
|
||||
break;
|
||||
case WLAN_CAPABILITY_DMG_TYPE_PBSS:
|
||||
conn.network_type = WMI_NETTYPE_P2P;
|
||||
break;
|
||||
default:
|
||||
wil_err(wil, "Unsupported BSS type, capability= 0x%04x\n",
|
||||
bss->capability);
|
||||
goto out;
|
||||
}
|
||||
if (rsn_eid) {
|
||||
conn.dot11_auth_mode = WMI_AUTH11_SHARED;
|
||||
conn.auth_mode = WMI_AUTH_WPA2_PSK;
|
||||
conn.pairwise_crypto_type = WMI_CRYPT_AES_GCMP;
|
||||
conn.pairwise_crypto_len = 16;
|
||||
} else {
|
||||
conn.dot11_auth_mode = WMI_AUTH11_OPEN;
|
||||
conn.auth_mode = WMI_AUTH_NONE;
|
||||
}
|
||||
|
||||
conn.ssid_len = min_t(u8, ssid_eid[1], 32);
|
||||
memcpy(conn.ssid, ssid_eid+2, conn.ssid_len);
|
||||
|
||||
ch = bss->channel->hw_value;
|
||||
if (ch == 0) {
|
||||
wil_err(wil, "BSS at unknown frequency %dMhz\n",
|
||||
bss->channel->center_freq);
|
||||
rc = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
conn.channel = ch - 1;
|
||||
|
||||
memcpy(conn.bssid, bss->bssid, 6);
|
||||
memcpy(conn.dst_mac, bss->bssid, 6);
|
||||
/*
|
||||
* FW don't support scan after connection attempt
|
||||
*/
|
||||
set_bit(wil_status_dontscan, &wil->status);
|
||||
|
||||
rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn));
|
||||
if (rc == 0) {
|
||||
/* Connect can take lots of time */
|
||||
mod_timer(&wil->connect_timer,
|
||||
jiffies + msecs_to_jiffies(2000));
|
||||
}
|
||||
|
||||
out:
|
||||
cfg80211_put_bss(bss);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int wil_cfg80211_disconnect(struct wiphy *wiphy,
|
||||
struct net_device *ndev,
|
||||
u16 reason_code)
|
||||
{
|
||||
int rc;
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
|
||||
rc = wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int wil_cfg80211_set_channel(struct wiphy *wiphy,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
struct wireless_dev *wdev = wil->wdev;
|
||||
|
||||
wdev->preset_chandef = *chandef;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil_cfg80211_add_key(struct wiphy *wiphy,
|
||||
struct net_device *ndev,
|
||||
u8 key_index, bool pairwise,
|
||||
const u8 *mac_addr,
|
||||
struct key_params *params)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
|
||||
/* group key is not used */
|
||||
if (!pairwise)
|
||||
return 0;
|
||||
|
||||
return wmi_add_cipher_key(wil, key_index, mac_addr,
|
||||
params->key_len, params->key);
|
||||
}
|
||||
|
||||
static int wil_cfg80211_del_key(struct wiphy *wiphy,
|
||||
struct net_device *ndev,
|
||||
u8 key_index, bool pairwise,
|
||||
const u8 *mac_addr)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
|
||||
/* group key is not used */
|
||||
if (!pairwise)
|
||||
return 0;
|
||||
|
||||
return wmi_del_cipher_key(wil, key_index, mac_addr);
|
||||
}
|
||||
|
||||
/* Need to be present or wiphy_new() will WARN */
|
||||
static int wil_cfg80211_set_default_key(struct wiphy *wiphy,
|
||||
struct net_device *ndev,
|
||||
u8 key_index, bool unicast,
|
||||
bool multicast)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil_cfg80211_start_ap(struct wiphy *wiphy,
|
||||
struct net_device *ndev,
|
||||
struct cfg80211_ap_settings *info)
|
||||
{
|
||||
int rc = 0;
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
struct wireless_dev *wdev = ndev->ieee80211_ptr;
|
||||
struct ieee80211_channel *channel = info->chandef.chan;
|
||||
struct cfg80211_beacon_data *bcon = &info->beacon;
|
||||
u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype);
|
||||
|
||||
if (!channel) {
|
||||
wil_err(wil, "AP: No channel???\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
wil_dbg(wil, "AP on Channel %d %d MHz, %s\n", channel->hw_value,
|
||||
channel->center_freq, info->privacy ? "secure" : "open");
|
||||
print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET,
|
||||
info->ssid, info->ssid_len);
|
||||
|
||||
rc = wil_reset(wil);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = wmi_set_ssid(wil, info->ssid_len, info->ssid);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = wmi_set_channel(wil, channel->hw_value);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* MAC address - pre-requisite for other commands */
|
||||
wmi_set_mac_address(wil, ndev->dev_addr);
|
||||
|
||||
/* IE's */
|
||||
/* bcon 'head IE's are not relevant for 60g band */
|
||||
wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len,
|
||||
bcon->beacon_ies);
|
||||
wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, bcon->proberesp_ies_len,
|
||||
bcon->proberesp_ies);
|
||||
wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len,
|
||||
bcon->assocresp_ies);
|
||||
|
||||
wil->secure_pcp = info->privacy;
|
||||
|
||||
rc = wmi_set_bcon(wil, info->beacon_interval, wmi_nettype);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Rx VRING. After MAC and beacon */
|
||||
rc = wil_rx_init(wil);
|
||||
|
||||
netif_carrier_on(ndev);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
|
||||
struct net_device *ndev)
|
||||
{
|
||||
int rc = 0;
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
struct wireless_dev *wdev = ndev->ieee80211_ptr;
|
||||
u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype);
|
||||
|
||||
/* To stop beaconing, set BI to 0 */
|
||||
rc = wmi_set_bcon(wil, 0, wmi_nettype);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static struct cfg80211_ops wil_cfg80211_ops = {
|
||||
.scan = wil_cfg80211_scan,
|
||||
.connect = wil_cfg80211_connect,
|
||||
.disconnect = wil_cfg80211_disconnect,
|
||||
.change_virtual_intf = wil_cfg80211_change_iface,
|
||||
.get_station = wil_cfg80211_get_station,
|
||||
.set_monitor_channel = wil_cfg80211_set_channel,
|
||||
.add_key = wil_cfg80211_add_key,
|
||||
.del_key = wil_cfg80211_del_key,
|
||||
.set_default_key = wil_cfg80211_set_default_key,
|
||||
/* AP mode */
|
||||
.start_ap = wil_cfg80211_start_ap,
|
||||
.stop_ap = wil_cfg80211_stop_ap,
|
||||
};
|
||||
|
||||
static void wil_wiphy_init(struct wiphy *wiphy)
|
||||
{
|
||||
/* TODO: set real value */
|
||||
wiphy->max_scan_ssids = 10;
|
||||
wiphy->max_num_pmkids = 0 /* TODO: */;
|
||||
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_AP) |
|
||||
BIT(NL80211_IFTYPE_MONITOR);
|
||||
/* TODO: enable P2P when integrated with supplicant:
|
||||
* BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO)
|
||||
*/
|
||||
wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
|
||||
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
|
||||
dev_warn(wiphy_dev(wiphy), "%s : flags = 0x%08x\n",
|
||||
__func__, wiphy->flags);
|
||||
wiphy->probe_resp_offload =
|
||||
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
|
||||
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
|
||||
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
|
||||
|
||||
wiphy->bands[IEEE80211_BAND_60GHZ] = &wil_band_60ghz;
|
||||
|
||||
/* TODO: figure this out */
|
||||
wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
|
||||
|
||||
wiphy->cipher_suites = wil_cipher_suites;
|
||||
wiphy->n_cipher_suites = ARRAY_SIZE(wil_cipher_suites);
|
||||
wiphy->mgmt_stypes = wil_mgmt_stypes;
|
||||
}
|
||||
|
||||
struct wireless_dev *wil_cfg80211_init(struct device *dev)
|
||||
{
|
||||
int rc = 0;
|
||||
struct wireless_dev *wdev;
|
||||
|
||||
wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
|
||||
if (!wdev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
wdev->wiphy = wiphy_new(&wil_cfg80211_ops,
|
||||
sizeof(struct wil6210_priv));
|
||||
if (!wdev->wiphy) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
set_wiphy_dev(wdev->wiphy, dev);
|
||||
wil_wiphy_init(wdev->wiphy);
|
||||
|
||||
rc = wiphy_register(wdev->wiphy);
|
||||
if (rc < 0)
|
||||
goto out_failed_reg;
|
||||
|
||||
return wdev;
|
||||
|
||||
out_failed_reg:
|
||||
wiphy_free(wdev->wiphy);
|
||||
out:
|
||||
kfree(wdev);
|
||||
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
void wil_wdev_free(struct wil6210_priv *wil)
|
||||
{
|
||||
struct wireless_dev *wdev = wil_to_wdev(wil);
|
||||
|
||||
if (!wdev)
|
||||
return;
|
||||
|
||||
wiphy_unregister(wdev->wiphy);
|
||||
wiphy_free(wdev->wiphy);
|
||||
kfree(wdev);
|
||||
}
|
30
drivers/net/wireless/ath/wil6210/dbg_hexdump.h
Normal file
30
drivers/net/wireless/ath/wil6210/dbg_hexdump.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#ifndef WIL_DBG_HEXDUMP_H_
|
||||
#define WIL_DBG_HEXDUMP_H_
|
||||
|
||||
#if defined(CONFIG_DYNAMIC_DEBUG)
|
||||
#define wil_dynamic_hex_dump(prefix_str, prefix_type, rowsize, \
|
||||
groupsize, buf, len, ascii) \
|
||||
do { \
|
||||
DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, \
|
||||
__builtin_constant_p(prefix_str) ? prefix_str : "hexdump");\
|
||||
if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT)) \
|
||||
print_hex_dump(KERN_DEBUG, prefix_str, \
|
||||
prefix_type, rowsize, groupsize, \
|
||||
buf, len, ascii); \
|
||||
} while (0)
|
||||
|
||||
#define wil_print_hex_dump_debug(prefix_str, prefix_type, rowsize, \
|
||||
groupsize, buf, len, ascii) \
|
||||
wil_dynamic_hex_dump(prefix_str, prefix_type, rowsize, \
|
||||
groupsize, buf, len, ascii)
|
||||
|
||||
#define print_hex_dump_bytes(prefix_str, prefix_type, buf, len) \
|
||||
wil_dynamic_hex_dump(prefix_str, prefix_type, 16, 1, buf, len, true)
|
||||
#else /* defined(CONFIG_DYNAMIC_DEBUG) */
|
||||
#define wil_print_hex_dump_debug(prefix_str, prefix_type, rowsize, \
|
||||
groupsize, buf, len, ascii) \
|
||||
print_hex_dump(KERN_DEBUG, prefix_str, prefix_type, rowsize, \
|
||||
groupsize, buf, len, ascii)
|
||||
#endif /* defined(CONFIG_DYNAMIC_DEBUG) */
|
||||
|
||||
#endif /* WIL_DBG_HEXDUMP_H_ */
|
603
drivers/net/wireless/ath/wil6210/debugfs.c
Normal file
603
drivers/net/wireless/ath/wil6210/debugfs.c
Normal file
|
@ -0,0 +1,603 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Qualcomm Atheros, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
#include "wil6210.h"
|
||||
#include "txrx.h"
|
||||
|
||||
/* Nasty hack. Better have per device instances */
|
||||
static u32 mem_addr;
|
||||
static u32 dbg_txdesc_index;
|
||||
|
||||
static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
|
||||
const char *name, struct vring *vring)
|
||||
{
|
||||
void __iomem *x = wmi_addr(wil, vring->hwtail);
|
||||
|
||||
seq_printf(s, "VRING %s = {\n", name);
|
||||
seq_printf(s, " pa = 0x%016llx\n", (unsigned long long)vring->pa);
|
||||
seq_printf(s, " va = 0x%p\n", vring->va);
|
||||
seq_printf(s, " size = %d\n", vring->size);
|
||||
seq_printf(s, " swtail = %d\n", vring->swtail);
|
||||
seq_printf(s, " swhead = %d\n", vring->swhead);
|
||||
seq_printf(s, " hwtail = [0x%08x] -> ", vring->hwtail);
|
||||
if (x)
|
||||
seq_printf(s, "0x%08x\n", ioread32(x));
|
||||
else
|
||||
seq_printf(s, "???\n");
|
||||
|
||||
if (vring->va && (vring->size < 1025)) {
|
||||
uint i;
|
||||
for (i = 0; i < vring->size; i++) {
|
||||
volatile struct vring_tx_desc *d = &vring->va[i].tx;
|
||||
if ((i % 64) == 0 && (i != 0))
|
||||
seq_printf(s, "\n");
|
||||
seq_printf(s, "%s", (d->dma.status & BIT(0)) ?
|
||||
"S" : (vring->ctx[i] ? "H" : "h"));
|
||||
}
|
||||
seq_printf(s, "\n");
|
||||
}
|
||||
seq_printf(s, "}\n");
|
||||
}
|
||||
|
||||
static int wil_vring_debugfs_show(struct seq_file *s, void *data)
|
||||
{
|
||||
uint i;
|
||||
struct wil6210_priv *wil = s->private;
|
||||
|
||||
wil_print_vring(s, wil, "rx", &wil->vring_rx);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
|
||||
struct vring *vring = &(wil->vring_tx[i]);
|
||||
if (vring->va) {
|
||||
char name[10];
|
||||
snprintf(name, sizeof(name), "tx_%2d", i);
|
||||
wil_print_vring(s, wil, name, vring);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil_vring_seq_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, wil_vring_debugfs_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_vring = {
|
||||
.open = wil_vring_seq_open,
|
||||
.release = single_release,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
};
|
||||
|
||||
static void wil_print_ring(struct seq_file *s, const char *prefix,
|
||||
void __iomem *off)
|
||||
{
|
||||
struct wil6210_priv *wil = s->private;
|
||||
struct wil6210_mbox_ring r;
|
||||
int rsize;
|
||||
uint i;
|
||||
|
||||
wil_memcpy_fromio_32(&r, off, sizeof(r));
|
||||
wil_mbox_ring_le2cpus(&r);
|
||||
/*
|
||||
* we just read memory block from NIC. This memory may be
|
||||
* garbage. Check validity before using it.
|
||||
*/
|
||||
rsize = r.size / sizeof(struct wil6210_mbox_ring_desc);
|
||||
|
||||
seq_printf(s, "ring %s = {\n", prefix);
|
||||
seq_printf(s, " base = 0x%08x\n", r.base);
|
||||
seq_printf(s, " size = 0x%04x bytes -> %d entries\n", r.size, rsize);
|
||||
seq_printf(s, " tail = 0x%08x\n", r.tail);
|
||||
seq_printf(s, " head = 0x%08x\n", r.head);
|
||||
seq_printf(s, " entry size = %d\n", r.entry_size);
|
||||
|
||||
if (r.size % sizeof(struct wil6210_mbox_ring_desc)) {
|
||||
seq_printf(s, " ??? size is not multiple of %zd, garbage?\n",
|
||||
sizeof(struct wil6210_mbox_ring_desc));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!wmi_addr(wil, r.base) ||
|
||||
!wmi_addr(wil, r.tail) ||
|
||||
!wmi_addr(wil, r.head)) {
|
||||
seq_printf(s, " ??? pointers are garbage?\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < rsize; i++) {
|
||||
struct wil6210_mbox_ring_desc d;
|
||||
struct wil6210_mbox_hdr hdr;
|
||||
size_t delta = i * sizeof(d);
|
||||
void __iomem *x = wil->csr + HOSTADDR(r.base) + delta;
|
||||
|
||||
wil_memcpy_fromio_32(&d, x, sizeof(d));
|
||||
|
||||
seq_printf(s, " [%2x] %s %s%s 0x%08x", i,
|
||||
d.sync ? "F" : "E",
|
||||
(r.tail - r.base == delta) ? "t" : " ",
|
||||
(r.head - r.base == delta) ? "h" : " ",
|
||||
le32_to_cpu(d.addr));
|
||||
if (0 == wmi_read_hdr(wil, d.addr, &hdr)) {
|
||||
u16 len = le16_to_cpu(hdr.len);
|
||||
seq_printf(s, " -> %04x %04x %04x %02x\n",
|
||||
le16_to_cpu(hdr.seq), len,
|
||||
le16_to_cpu(hdr.type), hdr.flags);
|
||||
if (len <= MAX_MBOXITEM_SIZE) {
|
||||
int n = 0;
|
||||
unsigned char printbuf[16 * 3 + 2];
|
||||
unsigned char databuf[MAX_MBOXITEM_SIZE];
|
||||
void __iomem *src = wmi_buffer(wil, d.addr) +
|
||||
sizeof(struct wil6210_mbox_hdr);
|
||||
/*
|
||||
* No need to check @src for validity -
|
||||
* we already validated @d.addr while
|
||||
* reading header
|
||||
*/
|
||||
wil_memcpy_fromio_32(databuf, src, len);
|
||||
while (n < len) {
|
||||
int l = min(len - n, 16);
|
||||
hex_dump_to_buffer(databuf + n, l,
|
||||
16, 1, printbuf,
|
||||
sizeof(printbuf),
|
||||
false);
|
||||
seq_printf(s, " : %s\n", printbuf);
|
||||
n += l;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
seq_printf(s, "\n");
|
||||
}
|
||||
}
|
||||
out:
|
||||
seq_printf(s, "}\n");
|
||||
}
|
||||
|
||||
static int wil_mbox_debugfs_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct wil6210_priv *wil = s->private;
|
||||
|
||||
wil_print_ring(s, "tx", wil->csr + HOST_MBOX +
|
||||
offsetof(struct wil6210_mbox_ctl, tx));
|
||||
wil_print_ring(s, "rx", wil->csr + HOST_MBOX +
|
||||
offsetof(struct wil6210_mbox_ctl, rx));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil_mbox_seq_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, wil_mbox_debugfs_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_mbox = {
|
||||
.open = wil_mbox_seq_open,
|
||||
.release = single_release,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
};
|
||||
|
||||
static int wil_debugfs_iomem_x32_set(void *data, u64 val)
|
||||
{
|
||||
iowrite32(val, (void __iomem *)data);
|
||||
wmb(); /* make sure write propagated to HW */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil_debugfs_iomem_x32_get(void *data, u64 *val)
|
||||
{
|
||||
*val = ioread32((void __iomem *)data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, wil_debugfs_iomem_x32_get,
|
||||
wil_debugfs_iomem_x32_set, "0x%08llx\n");
|
||||
|
||||
static struct dentry *wil_debugfs_create_iomem_x32(const char *name,
|
||||
mode_t mode,
|
||||
struct dentry *parent,
|
||||
void __iomem *value)
|
||||
{
|
||||
return debugfs_create_file(name, mode, parent, (void * __force)value,
|
||||
&fops_iomem_x32);
|
||||
}
|
||||
|
||||
static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil,
|
||||
const char *name,
|
||||
struct dentry *parent, u32 off)
|
||||
{
|
||||
struct dentry *d = debugfs_create_dir(name, parent);
|
||||
|
||||
if (IS_ERR_OR_NULL(d))
|
||||
return -ENODEV;
|
||||
|
||||
wil_debugfs_create_iomem_x32("ICC", S_IRUGO | S_IWUSR, d,
|
||||
wil->csr + off);
|
||||
wil_debugfs_create_iomem_x32("ICR", S_IRUGO | S_IWUSR, d,
|
||||
wil->csr + off + 4);
|
||||
wil_debugfs_create_iomem_x32("ICM", S_IRUGO | S_IWUSR, d,
|
||||
wil->csr + off + 8);
|
||||
wil_debugfs_create_iomem_x32("ICS", S_IWUSR, d,
|
||||
wil->csr + off + 12);
|
||||
wil_debugfs_create_iomem_x32("IMV", S_IRUGO | S_IWUSR, d,
|
||||
wil->csr + off + 16);
|
||||
wil_debugfs_create_iomem_x32("IMS", S_IWUSR, d,
|
||||
wil->csr + off + 20);
|
||||
wil_debugfs_create_iomem_x32("IMC", S_IWUSR, d,
|
||||
wil->csr + off + 24);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil,
|
||||
struct dentry *parent)
|
||||
{
|
||||
struct dentry *d = debugfs_create_dir("PSEUDO_ISR", parent);
|
||||
|
||||
if (IS_ERR_OR_NULL(d))
|
||||
return -ENODEV;
|
||||
|
||||
wil_debugfs_create_iomem_x32("CAUSE", S_IRUGO, d, wil->csr +
|
||||
HOSTADDR(RGF_DMA_PSEUDO_CAUSE));
|
||||
wil_debugfs_create_iomem_x32("MASK_SW", S_IRUGO, d, wil->csr +
|
||||
HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW));
|
||||
wil_debugfs_create_iomem_x32("MASK_FW", S_IRUGO, d, wil->csr +
|
||||
HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil,
|
||||
struct dentry *parent)
|
||||
{
|
||||
struct dentry *d = debugfs_create_dir("ITR_CNT", parent);
|
||||
|
||||
if (IS_ERR_OR_NULL(d))
|
||||
return -ENODEV;
|
||||
|
||||
wil_debugfs_create_iomem_x32("TRSH", S_IRUGO, d, wil->csr +
|
||||
HOSTADDR(RGF_DMA_ITR_CNT_TRSH));
|
||||
wil_debugfs_create_iomem_x32("DATA", S_IRUGO, d, wil->csr +
|
||||
HOSTADDR(RGF_DMA_ITR_CNT_DATA));
|
||||
wil_debugfs_create_iomem_x32("CTL", S_IRUGO, d, wil->csr +
|
||||
HOSTADDR(RGF_DMA_ITR_CNT_CRL));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil_memread_debugfs_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct wil6210_priv *wil = s->private;
|
||||
void __iomem *a = wmi_buffer(wil, cpu_to_le32(mem_addr));
|
||||
|
||||
if (a)
|
||||
seq_printf(s, "[0x%08x] = 0x%08x\n", mem_addr, ioread32(a));
|
||||
else
|
||||
seq_printf(s, "[0x%08x] = INVALID\n", mem_addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil_memread_seq_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, wil_memread_debugfs_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_memread = {
|
||||
.open = wil_memread_seq_open,
|
||||
.release = single_release,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
};
|
||||
|
||||
static int wil_default_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
if (inode->i_private)
|
||||
file->private_data = inode->i_private;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
enum { max_count = 4096 };
|
||||
struct debugfs_blob_wrapper *blob = file->private_data;
|
||||
loff_t pos = *ppos;
|
||||
size_t available = blob->size;
|
||||
void *buf;
|
||||
size_t ret;
|
||||
|
||||
if (pos < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (pos >= available || !count)
|
||||
return 0;
|
||||
|
||||
if (count > available - pos)
|
||||
count = available - pos;
|
||||
if (count > max_count)
|
||||
count = max_count;
|
||||
|
||||
buf = kmalloc(count, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
wil_memcpy_fromio_32(buf, (const volatile void __iomem *)blob->data +
|
||||
pos, count);
|
||||
|
||||
ret = copy_to_user(user_buf, buf, count);
|
||||
kfree(buf);
|
||||
if (ret == count)
|
||||
return -EFAULT;
|
||||
|
||||
count -= ret;
|
||||
*ppos = pos + count;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_ioblob = {
|
||||
.read = wil_read_file_ioblob,
|
||||
.open = wil_default_open,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static
|
||||
struct dentry *wil_debugfs_create_ioblob(const char *name,
|
||||
mode_t mode,
|
||||
struct dentry *parent,
|
||||
struct debugfs_blob_wrapper *blob)
|
||||
{
|
||||
return debugfs_create_file(name, mode, parent, blob, &fops_ioblob);
|
||||
}
|
||||
/*---reset---*/
|
||||
static ssize_t wil_write_file_reset(struct file *file, const char __user *buf,
|
||||
size_t len, loff_t *ppos)
|
||||
{
|
||||
struct wil6210_priv *wil = file->private_data;
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
|
||||
/**
|
||||
* BUG:
|
||||
* this code does NOT sync device state with the rest of system
|
||||
* use with care, debug only!!!
|
||||
*/
|
||||
rtnl_lock();
|
||||
dev_close(ndev);
|
||||
ndev->flags &= ~IFF_UP;
|
||||
rtnl_unlock();
|
||||
wil_reset(wil);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_reset = {
|
||||
.write = wil_write_file_reset,
|
||||
.open = wil_default_open,
|
||||
};
|
||||
/*---------Tx descriptor------------*/
|
||||
|
||||
static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct wil6210_priv *wil = s->private;
|
||||
struct vring *vring = &(wil->vring_tx[0]);
|
||||
|
||||
if (!vring->va) {
|
||||
seq_printf(s, "No Tx VRING\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dbg_txdesc_index < vring->size) {
|
||||
volatile struct vring_tx_desc *d =
|
||||
&(vring->va[dbg_txdesc_index].tx);
|
||||
volatile u32 *u = (volatile u32 *)d;
|
||||
struct sk_buff *skb = vring->ctx[dbg_txdesc_index];
|
||||
|
||||
seq_printf(s, "Tx[%3d] = {\n", dbg_txdesc_index);
|
||||
seq_printf(s, " MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n",
|
||||
u[0], u[1], u[2], u[3]);
|
||||
seq_printf(s, " DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n",
|
||||
u[4], u[5], u[6], u[7]);
|
||||
seq_printf(s, " SKB = %p\n", skb);
|
||||
|
||||
if (skb) {
|
||||
unsigned char printbuf[16 * 3 + 2];
|
||||
int i = 0;
|
||||
int len = skb_headlen(skb);
|
||||
void *p = skb->data;
|
||||
|
||||
seq_printf(s, " len = %d\n", len);
|
||||
|
||||
while (i < len) {
|
||||
int l = min(len - i, 16);
|
||||
hex_dump_to_buffer(p + i, l, 16, 1, printbuf,
|
||||
sizeof(printbuf), false);
|
||||
seq_printf(s, " : %s\n", printbuf);
|
||||
i += l;
|
||||
}
|
||||
}
|
||||
seq_printf(s, "}\n");
|
||||
} else {
|
||||
seq_printf(s, "TxDesc index (%d) >= size (%d)\n",
|
||||
dbg_txdesc_index, vring->size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil_txdesc_seq_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, wil_txdesc_debugfs_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_txdesc = {
|
||||
.open = wil_txdesc_seq_open,
|
||||
.release = single_release,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
};
|
||||
|
||||
/*---------beamforming------------*/
|
||||
static int wil_bf_debugfs_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct wil6210_priv *wil = s->private;
|
||||
seq_printf(s,
|
||||
"TSF : 0x%016llx\n"
|
||||
"TxMCS : %d\n"
|
||||
"Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n",
|
||||
wil->stats.tsf, wil->stats.bf_mcs,
|
||||
wil->stats.my_rx_sector, wil->stats.my_tx_sector,
|
||||
wil->stats.peer_rx_sector, wil->stats.peer_tx_sector);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil_bf_seq_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, wil_bf_debugfs_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_bf = {
|
||||
.open = wil_bf_seq_open,
|
||||
.release = single_release,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
};
|
||||
/*---------SSID------------*/
|
||||
static ssize_t wil_read_file_ssid(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct wil6210_priv *wil = file->private_data;
|
||||
struct wireless_dev *wdev = wil_to_wdev(wil);
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos,
|
||||
wdev->ssid, wdev->ssid_len);
|
||||
}
|
||||
|
||||
static ssize_t wil_write_file_ssid(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct wil6210_priv *wil = file->private_data;
|
||||
struct wireless_dev *wdev = wil_to_wdev(wil);
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
|
||||
if (*ppos != 0) {
|
||||
wil_err(wil, "Unable to set SSID substring from [%d]\n",
|
||||
(int)*ppos);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (count > sizeof(wdev->ssid)) {
|
||||
wil_err(wil, "SSID too long, len = %d\n", (int)count);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (netif_running(ndev)) {
|
||||
wil_err(wil, "Unable to change SSID on running interface\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
wdev->ssid_len = count;
|
||||
return simple_write_to_buffer(wdev->ssid, wdev->ssid_len, ppos,
|
||||
buf, count);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_ssid = {
|
||||
.read = wil_read_file_ssid,
|
||||
.write = wil_write_file_ssid,
|
||||
.open = wil_default_open,
|
||||
};
|
||||
|
||||
/*----------------*/
|
||||
int wil6210_debugfs_init(struct wil6210_priv *wil)
|
||||
{
|
||||
struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME,
|
||||
wil_to_wiphy(wil)->debugfsdir);
|
||||
|
||||
if (IS_ERR_OR_NULL(dbg))
|
||||
return -ENODEV;
|
||||
|
||||
debugfs_create_file("mbox", S_IRUGO, dbg, wil, &fops_mbox);
|
||||
debugfs_create_file("vrings", S_IRUGO, dbg, wil, &fops_vring);
|
||||
debugfs_create_file("txdesc", S_IRUGO, dbg, wil, &fops_txdesc);
|
||||
debugfs_create_u32("txdesc_index", S_IRUGO | S_IWUSR, dbg,
|
||||
&dbg_txdesc_index);
|
||||
debugfs_create_file("bf", S_IRUGO, dbg, wil, &fops_bf);
|
||||
debugfs_create_file("ssid", S_IRUGO | S_IWUSR, dbg, wil, &fops_ssid);
|
||||
debugfs_create_u32("secure_pcp", S_IRUGO | S_IWUSR, dbg,
|
||||
&wil->secure_pcp);
|
||||
|
||||
wil6210_debugfs_create_ISR(wil, "USER_ICR", dbg,
|
||||
HOSTADDR(RGF_USER_USER_ICR));
|
||||
wil6210_debugfs_create_ISR(wil, "DMA_EP_TX_ICR", dbg,
|
||||
HOSTADDR(RGF_DMA_EP_TX_ICR));
|
||||
wil6210_debugfs_create_ISR(wil, "DMA_EP_RX_ICR", dbg,
|
||||
HOSTADDR(RGF_DMA_EP_RX_ICR));
|
||||
wil6210_debugfs_create_ISR(wil, "DMA_EP_MISC_ICR", dbg,
|
||||
HOSTADDR(RGF_DMA_EP_MISC_ICR));
|
||||
wil6210_debugfs_create_pseudo_ISR(wil, dbg);
|
||||
wil6210_debugfs_create_ITR_CNT(wil, dbg);
|
||||
|
||||
debugfs_create_u32("mem_addr", S_IRUGO | S_IWUSR, dbg, &mem_addr);
|
||||
debugfs_create_file("mem_val", S_IRUGO, dbg, wil, &fops_memread);
|
||||
|
||||
debugfs_create_file("reset", S_IWUSR, dbg, wil, &fops_reset);
|
||||
|
||||
wil->rgf_blob.data = (void * __force)wil->csr + 0;
|
||||
wil->rgf_blob.size = 0xa000;
|
||||
wil_debugfs_create_ioblob("blob_rgf", S_IRUGO, dbg, &wil->rgf_blob);
|
||||
|
||||
wil->fw_code_blob.data = (void * __force)wil->csr + 0x40000;
|
||||
wil->fw_code_blob.size = 0x40000;
|
||||
wil_debugfs_create_ioblob("blob_fw_code", S_IRUGO, dbg,
|
||||
&wil->fw_code_blob);
|
||||
|
||||
wil->fw_data_blob.data = (void * __force)wil->csr + 0x80000;
|
||||
wil->fw_data_blob.size = 0x8000;
|
||||
wil_debugfs_create_ioblob("blob_fw_data", S_IRUGO, dbg,
|
||||
&wil->fw_data_blob);
|
||||
|
||||
wil->fw_peri_blob.data = (void * __force)wil->csr + 0x88000;
|
||||
wil->fw_peri_blob.size = 0x18000;
|
||||
wil_debugfs_create_ioblob("blob_fw_peri", S_IRUGO, dbg,
|
||||
&wil->fw_peri_blob);
|
||||
|
||||
wil->uc_code_blob.data = (void * __force)wil->csr + 0xa0000;
|
||||
wil->uc_code_blob.size = 0x10000;
|
||||
wil_debugfs_create_ioblob("blob_uc_code", S_IRUGO, dbg,
|
||||
&wil->uc_code_blob);
|
||||
|
||||
wil->uc_data_blob.data = (void * __force)wil->csr + 0xb0000;
|
||||
wil->uc_data_blob.size = 0x4000;
|
||||
wil_debugfs_create_ioblob("blob_uc_data", S_IRUGO, dbg,
|
||||
&wil->uc_data_blob);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wil6210_debugfs_remove(struct wil6210_priv *wil)
|
||||
{
|
||||
debugfs_remove_recursive(wil->debug);
|
||||
wil->debug = NULL;
|
||||
}
|
471
drivers/net/wireless/ath/wil6210/interrupt.c
Normal file
471
drivers/net/wireless/ath/wil6210/interrupt.c
Normal file
|
@ -0,0 +1,471 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Qualcomm Atheros, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "wil6210.h"
|
||||
|
||||
/**
|
||||
* Theory of operation:
|
||||
*
|
||||
* There is ISR pseudo-cause register,
|
||||
* dma_rgf->DMA_RGF.PSEUDO_CAUSE.PSEUDO_CAUSE
|
||||
* Its bits represents OR'ed bits from 3 real ISR registers:
|
||||
* TX, RX, and MISC.
|
||||
*
|
||||
* Registers may be configured to either "write 1 to clear" or
|
||||
* "clear on read" mode
|
||||
*
|
||||
* When handling interrupt, one have to mask/unmask interrupts for the
|
||||
* real ISR registers, or hardware may malfunction.
|
||||
*
|
||||
*/
|
||||
|
||||
#define WIL6210_IRQ_DISABLE (0xFFFFFFFFUL)
|
||||
#define WIL6210_IMC_RX BIT_DMA_EP_RX_ICR_RX_DONE
|
||||
#define WIL6210_IMC_TX (BIT_DMA_EP_TX_ICR_TX_DONE | \
|
||||
BIT_DMA_EP_TX_ICR_TX_DONE_N(0))
|
||||
#define WIL6210_IMC_MISC (ISR_MISC_FW_READY | ISR_MISC_MBOX_EVT)
|
||||
|
||||
#define WIL6210_IRQ_PSEUDO_MASK (u32)(~(BIT_DMA_PSEUDO_CAUSE_RX | \
|
||||
BIT_DMA_PSEUDO_CAUSE_TX | \
|
||||
BIT_DMA_PSEUDO_CAUSE_MISC))
|
||||
|
||||
#if defined(CONFIG_WIL6210_ISR_COR)
|
||||
/* configure to Clear-On-Read mode */
|
||||
#define WIL_ICR_ICC_VALUE (0xFFFFFFFFUL)
|
||||
|
||||
static inline void wil_icr_clear(u32 x, void __iomem *addr)
|
||||
{
|
||||
|
||||
}
|
||||
#else /* defined(CONFIG_WIL6210_ISR_COR) */
|
||||
/* configure to Write-1-to-Clear mode */
|
||||
#define WIL_ICR_ICC_VALUE (0UL)
|
||||
|
||||
static inline void wil_icr_clear(u32 x, void __iomem *addr)
|
||||
{
|
||||
iowrite32(x, addr);
|
||||
}
|
||||
#endif /* defined(CONFIG_WIL6210_ISR_COR) */
|
||||
|
||||
static inline u32 wil_ioread32_and_clear(void __iomem *addr)
|
||||
{
|
||||
u32 x = ioread32(addr);
|
||||
|
||||
wil_icr_clear(x, addr);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static void wil6210_mask_irq_tx(struct wil6210_priv *wil)
|
||||
{
|
||||
iowrite32(WIL6210_IRQ_DISABLE, wil->csr +
|
||||
HOSTADDR(RGF_DMA_EP_TX_ICR) +
|
||||
offsetof(struct RGF_ICR, IMS));
|
||||
}
|
||||
|
||||
static void wil6210_mask_irq_rx(struct wil6210_priv *wil)
|
||||
{
|
||||
iowrite32(WIL6210_IRQ_DISABLE, wil->csr +
|
||||
HOSTADDR(RGF_DMA_EP_RX_ICR) +
|
||||
offsetof(struct RGF_ICR, IMS));
|
||||
}
|
||||
|
||||
static void wil6210_mask_irq_misc(struct wil6210_priv *wil)
|
||||
{
|
||||
iowrite32(WIL6210_IRQ_DISABLE, wil->csr +
|
||||
HOSTADDR(RGF_DMA_EP_MISC_ICR) +
|
||||
offsetof(struct RGF_ICR, IMS));
|
||||
}
|
||||
|
||||
static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil)
|
||||
{
|
||||
wil_dbg_IRQ(wil, "%s()\n", __func__);
|
||||
|
||||
iowrite32(WIL6210_IRQ_DISABLE, wil->csr +
|
||||
HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW));
|
||||
|
||||
clear_bit(wil_status_irqen, &wil->status);
|
||||
}
|
||||
|
||||
static void wil6210_unmask_irq_tx(struct wil6210_priv *wil)
|
||||
{
|
||||
iowrite32(WIL6210_IMC_TX, wil->csr +
|
||||
HOSTADDR(RGF_DMA_EP_TX_ICR) +
|
||||
offsetof(struct RGF_ICR, IMC));
|
||||
}
|
||||
|
||||
static void wil6210_unmask_irq_rx(struct wil6210_priv *wil)
|
||||
{
|
||||
iowrite32(WIL6210_IMC_RX, wil->csr +
|
||||
HOSTADDR(RGF_DMA_EP_RX_ICR) +
|
||||
offsetof(struct RGF_ICR, IMC));
|
||||
}
|
||||
|
||||
static void wil6210_unmask_irq_misc(struct wil6210_priv *wil)
|
||||
{
|
||||
iowrite32(WIL6210_IMC_MISC, wil->csr +
|
||||
HOSTADDR(RGF_DMA_EP_MISC_ICR) +
|
||||
offsetof(struct RGF_ICR, IMC));
|
||||
}
|
||||
|
||||
static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil)
|
||||
{
|
||||
wil_dbg_IRQ(wil, "%s()\n", __func__);
|
||||
|
||||
set_bit(wil_status_irqen, &wil->status);
|
||||
|
||||
iowrite32(WIL6210_IRQ_PSEUDO_MASK, wil->csr +
|
||||
HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW));
|
||||
}
|
||||
|
||||
void wil6210_disable_irq(struct wil6210_priv *wil)
|
||||
{
|
||||
wil_dbg_IRQ(wil, "%s()\n", __func__);
|
||||
|
||||
wil6210_mask_irq_tx(wil);
|
||||
wil6210_mask_irq_rx(wil);
|
||||
wil6210_mask_irq_misc(wil);
|
||||
wil6210_mask_irq_pseudo(wil);
|
||||
}
|
||||
|
||||
void wil6210_enable_irq(struct wil6210_priv *wil)
|
||||
{
|
||||
wil_dbg_IRQ(wil, "%s()\n", __func__);
|
||||
|
||||
iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_RX_ICR) +
|
||||
offsetof(struct RGF_ICR, ICC));
|
||||
iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_TX_ICR) +
|
||||
offsetof(struct RGF_ICR, ICC));
|
||||
iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) +
|
||||
offsetof(struct RGF_ICR, ICC));
|
||||
|
||||
wil6210_unmask_irq_pseudo(wil);
|
||||
wil6210_unmask_irq_tx(wil);
|
||||
wil6210_unmask_irq_rx(wil);
|
||||
wil6210_unmask_irq_misc(wil);
|
||||
}
|
||||
|
||||
static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
|
||||
{
|
||||
struct wil6210_priv *wil = cookie;
|
||||
u32 isr = wil_ioread32_and_clear(wil->csr +
|
||||
HOSTADDR(RGF_DMA_EP_RX_ICR) +
|
||||
offsetof(struct RGF_ICR, ICR));
|
||||
|
||||
wil_dbg_IRQ(wil, "ISR RX 0x%08x\n", isr);
|
||||
|
||||
if (!isr) {
|
||||
wil_err(wil, "spurious IRQ: RX\n");
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
wil6210_mask_irq_rx(wil);
|
||||
|
||||
if (isr & BIT_DMA_EP_RX_ICR_RX_DONE) {
|
||||
wil_dbg_IRQ(wil, "RX done\n");
|
||||
isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE;
|
||||
wil_rx_handle(wil);
|
||||
}
|
||||
|
||||
if (isr)
|
||||
wil_err(wil, "un-handled RX ISR bits 0x%08x\n", isr);
|
||||
|
||||
wil6210_unmask_irq_rx(wil);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
|
||||
{
|
||||
struct wil6210_priv *wil = cookie;
|
||||
u32 isr = wil_ioread32_and_clear(wil->csr +
|
||||
HOSTADDR(RGF_DMA_EP_TX_ICR) +
|
||||
offsetof(struct RGF_ICR, ICR));
|
||||
|
||||
wil_dbg_IRQ(wil, "ISR TX 0x%08x\n", isr);
|
||||
|
||||
if (!isr) {
|
||||
wil_err(wil, "spurious IRQ: TX\n");
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
wil6210_mask_irq_tx(wil);
|
||||
|
||||
if (isr & BIT_DMA_EP_TX_ICR_TX_DONE) {
|
||||
uint i;
|
||||
wil_dbg_IRQ(wil, "TX done\n");
|
||||
isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE;
|
||||
for (i = 0; i < 24; i++) {
|
||||
u32 mask = BIT_DMA_EP_TX_ICR_TX_DONE_N(i);
|
||||
if (isr & mask) {
|
||||
isr &= ~mask;
|
||||
wil_dbg_IRQ(wil, "TX done(%i)\n", i);
|
||||
wil_tx_complete(wil, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isr)
|
||||
wil_err(wil, "un-handled TX ISR bits 0x%08x\n", isr);
|
||||
|
||||
wil6210_unmask_irq_tx(wil);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
|
||||
{
|
||||
struct wil6210_priv *wil = cookie;
|
||||
u32 isr = wil_ioread32_and_clear(wil->csr +
|
||||
HOSTADDR(RGF_DMA_EP_MISC_ICR) +
|
||||
offsetof(struct RGF_ICR, ICR));
|
||||
|
||||
wil_dbg_IRQ(wil, "ISR MISC 0x%08x\n", isr);
|
||||
|
||||
if (!isr) {
|
||||
wil_err(wil, "spurious IRQ: MISC\n");
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
wil6210_mask_irq_misc(wil);
|
||||
|
||||
if (isr & ISR_MISC_FW_READY) {
|
||||
wil_dbg_IRQ(wil, "IRQ: FW ready\n");
|
||||
/**
|
||||
* Actual FW ready indicated by the
|
||||
* WMI_FW_READY_EVENTID
|
||||
*/
|
||||
isr &= ~ISR_MISC_FW_READY;
|
||||
}
|
||||
|
||||
wil->isr_misc = isr;
|
||||
|
||||
if (isr) {
|
||||
return IRQ_WAKE_THREAD;
|
||||
} else {
|
||||
wil6210_unmask_irq_misc(wil);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie)
|
||||
{
|
||||
struct wil6210_priv *wil = cookie;
|
||||
u32 isr = wil->isr_misc;
|
||||
|
||||
wil_dbg_IRQ(wil, "Thread ISR MISC 0x%08x\n", isr);
|
||||
|
||||
if (isr & ISR_MISC_MBOX_EVT) {
|
||||
wil_dbg_IRQ(wil, "MBOX event\n");
|
||||
wmi_recv_cmd(wil);
|
||||
isr &= ~ISR_MISC_MBOX_EVT;
|
||||
}
|
||||
|
||||
if (isr)
|
||||
wil_err(wil, "un-handled MISC ISR bits 0x%08x\n", isr);
|
||||
|
||||
wil->isr_misc = 0;
|
||||
|
||||
wil6210_unmask_irq_misc(wil);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* thread IRQ handler
|
||||
*/
|
||||
static irqreturn_t wil6210_thread_irq(int irq, void *cookie)
|
||||
{
|
||||
struct wil6210_priv *wil = cookie;
|
||||
|
||||
wil_dbg_IRQ(wil, "Thread IRQ\n");
|
||||
/* Discover real IRQ cause */
|
||||
if (wil->isr_misc)
|
||||
wil6210_irq_misc_thread(irq, cookie);
|
||||
|
||||
wil6210_unmask_irq_pseudo(wil);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* DEBUG
|
||||
* There is subtle bug in hardware that causes IRQ to raise when it should be
|
||||
* masked. It is quite rare and hard to debug.
|
||||
*
|
||||
* Catch irq issue if it happens and print all I can.
|
||||
*/
|
||||
static int wil6210_debug_irq_mask(struct wil6210_priv *wil, u32 pseudo_cause)
|
||||
{
|
||||
if (!test_bit(wil_status_irqen, &wil->status)) {
|
||||
u32 icm_rx = wil_ioread32_and_clear(wil->csr +
|
||||
HOSTADDR(RGF_DMA_EP_RX_ICR) +
|
||||
offsetof(struct RGF_ICR, ICM));
|
||||
u32 icr_rx = wil_ioread32_and_clear(wil->csr +
|
||||
HOSTADDR(RGF_DMA_EP_RX_ICR) +
|
||||
offsetof(struct RGF_ICR, ICR));
|
||||
u32 imv_rx = ioread32(wil->csr +
|
||||
HOSTADDR(RGF_DMA_EP_RX_ICR) +
|
||||
offsetof(struct RGF_ICR, IMV));
|
||||
u32 icm_tx = wil_ioread32_and_clear(wil->csr +
|
||||
HOSTADDR(RGF_DMA_EP_TX_ICR) +
|
||||
offsetof(struct RGF_ICR, ICM));
|
||||
u32 icr_tx = wil_ioread32_and_clear(wil->csr +
|
||||
HOSTADDR(RGF_DMA_EP_TX_ICR) +
|
||||
offsetof(struct RGF_ICR, ICR));
|
||||
u32 imv_tx = ioread32(wil->csr +
|
||||
HOSTADDR(RGF_DMA_EP_TX_ICR) +
|
||||
offsetof(struct RGF_ICR, IMV));
|
||||
u32 icm_misc = wil_ioread32_and_clear(wil->csr +
|
||||
HOSTADDR(RGF_DMA_EP_MISC_ICR) +
|
||||
offsetof(struct RGF_ICR, ICM));
|
||||
u32 icr_misc = wil_ioread32_and_clear(wil->csr +
|
||||
HOSTADDR(RGF_DMA_EP_MISC_ICR) +
|
||||
offsetof(struct RGF_ICR, ICR));
|
||||
u32 imv_misc = ioread32(wil->csr +
|
||||
HOSTADDR(RGF_DMA_EP_MISC_ICR) +
|
||||
offsetof(struct RGF_ICR, IMV));
|
||||
wil_err(wil, "IRQ when it should be masked: pseudo 0x%08x\n"
|
||||
"Rx icm:icr:imv 0x%08x 0x%08x 0x%08x\n"
|
||||
"Tx icm:icr:imv 0x%08x 0x%08x 0x%08x\n"
|
||||
"Misc icm:icr:imv 0x%08x 0x%08x 0x%08x\n",
|
||||
pseudo_cause,
|
||||
icm_rx, icr_rx, imv_rx,
|
||||
icm_tx, icr_tx, imv_tx,
|
||||
icm_misc, icr_misc, imv_misc);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t wil6210_hardirq(int irq, void *cookie)
|
||||
{
|
||||
irqreturn_t rc = IRQ_HANDLED;
|
||||
struct wil6210_priv *wil = cookie;
|
||||
u32 pseudo_cause = ioread32(wil->csr + HOSTADDR(RGF_DMA_PSEUDO_CAUSE));
|
||||
|
||||
/**
|
||||
* pseudo_cause is Clear-On-Read, no need to ACK
|
||||
*/
|
||||
if ((pseudo_cause == 0) || ((pseudo_cause & 0xff) == 0xff))
|
||||
return IRQ_NONE;
|
||||
|
||||
/* FIXME: IRQ mask debug */
|
||||
if (wil6210_debug_irq_mask(wil, pseudo_cause))
|
||||
return IRQ_NONE;
|
||||
|
||||
wil6210_mask_irq_pseudo(wil);
|
||||
|
||||
/* Discover real IRQ cause
|
||||
* There are 2 possible phases for every IRQ:
|
||||
* - hard IRQ handler called right here
|
||||
* - threaded handler called later
|
||||
*
|
||||
* Hard IRQ handler reads and clears ISR.
|
||||
*
|
||||
* If threaded handler requested, hard IRQ handler
|
||||
* returns IRQ_WAKE_THREAD and saves ISR register value
|
||||
* for the threaded handler use.
|
||||
*
|
||||
* voting for wake thread - need at least 1 vote
|
||||
*/
|
||||
if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_RX) &&
|
||||
(wil6210_irq_rx(irq, cookie) == IRQ_WAKE_THREAD))
|
||||
rc = IRQ_WAKE_THREAD;
|
||||
|
||||
if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_TX) &&
|
||||
(wil6210_irq_tx(irq, cookie) == IRQ_WAKE_THREAD))
|
||||
rc = IRQ_WAKE_THREAD;
|
||||
|
||||
if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_MISC) &&
|
||||
(wil6210_irq_misc(irq, cookie) == IRQ_WAKE_THREAD))
|
||||
rc = IRQ_WAKE_THREAD;
|
||||
|
||||
/* if thread is requested, it will unmask IRQ */
|
||||
if (rc != IRQ_WAKE_THREAD)
|
||||
wil6210_unmask_irq_pseudo(wil);
|
||||
|
||||
wil_dbg_IRQ(wil, "Hard IRQ 0x%08x\n", pseudo_cause);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int wil6210_request_3msi(struct wil6210_priv *wil, int irq)
|
||||
{
|
||||
int rc;
|
||||
/*
|
||||
* IRQ's are in the following order:
|
||||
* - Tx
|
||||
* - Rx
|
||||
* - Misc
|
||||
*/
|
||||
|
||||
rc = request_irq(irq, wil6210_irq_tx, IRQF_SHARED,
|
||||
WIL_NAME"_tx", wil);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = request_irq(irq + 1, wil6210_irq_rx, IRQF_SHARED,
|
||||
WIL_NAME"_rx", wil);
|
||||
if (rc)
|
||||
goto free0;
|
||||
|
||||
rc = request_threaded_irq(irq + 2, wil6210_irq_misc,
|
||||
wil6210_irq_misc_thread,
|
||||
IRQF_SHARED, WIL_NAME"_misc", wil);
|
||||
if (rc)
|
||||
goto free1;
|
||||
|
||||
return 0;
|
||||
/* error branch */
|
||||
free1:
|
||||
free_irq(irq + 1, wil);
|
||||
free0:
|
||||
free_irq(irq, wil);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int wil6210_init_irq(struct wil6210_priv *wil, int irq)
|
||||
{
|
||||
int rc;
|
||||
if (wil->n_msi == 3)
|
||||
rc = wil6210_request_3msi(wil, irq);
|
||||
else
|
||||
rc = request_threaded_irq(irq, wil6210_hardirq,
|
||||
wil6210_thread_irq,
|
||||
wil->n_msi ? 0 : IRQF_SHARED,
|
||||
WIL_NAME, wil);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
wil6210_enable_irq(wil);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wil6210_fini_irq(struct wil6210_priv *wil, int irq)
|
||||
{
|
||||
wil6210_disable_irq(wil);
|
||||
free_irq(irq, wil);
|
||||
if (wil->n_msi == 3) {
|
||||
free_irq(irq + 1, wil);
|
||||
free_irq(irq + 2, wil);
|
||||
}
|
||||
}
|
407
drivers/net/wireless/ath/wil6210/main.c
Normal file
407
drivers/net/wireless/ath/wil6210/main.c
Normal file
|
@ -0,0 +1,407 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Qualcomm Atheros, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/ieee80211.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/if_arp.h>
|
||||
|
||||
#include "wil6210.h"
|
||||
|
||||
/*
|
||||
* Due to a hardware issue,
|
||||
* one has to read/write to/from NIC in 32-bit chunks;
|
||||
* regular memcpy_fromio and siblings will
|
||||
* not work on 64-bit platform - it uses 64-bit transactions
|
||||
*
|
||||
* Force 32-bit transactions to enable NIC on 64-bit platforms
|
||||
*
|
||||
* To avoid byte swap on big endian host, __raw_{read|write}l
|
||||
* should be used - {read|write}l would swap bytes to provide
|
||||
* little endian on PCI value in host endianness.
|
||||
*/
|
||||
void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src,
|
||||
size_t count)
|
||||
{
|
||||
u32 *d = dst;
|
||||
const volatile u32 __iomem *s = src;
|
||||
|
||||
/* size_t is unsigned, if (count%4 != 0) it will wrap */
|
||||
for (count += 4; count > 4; count -= 4)
|
||||
*d++ = __raw_readl(s++);
|
||||
}
|
||||
|
||||
void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
|
||||
size_t count)
|
||||
{
|
||||
volatile u32 __iomem *d = dst;
|
||||
const u32 *s = src;
|
||||
|
||||
for (count += 4; count > 4; count -= 4)
|
||||
__raw_writel(*s++, d++);
|
||||
}
|
||||
|
||||
static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid)
|
||||
{
|
||||
uint i;
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct wireless_dev *wdev = wil->wdev;
|
||||
|
||||
wil_dbg(wil, "%s()\n", __func__);
|
||||
|
||||
wil_link_off(wil);
|
||||
clear_bit(wil_status_fwconnected, &wil->status);
|
||||
|
||||
switch (wdev->sme_state) {
|
||||
case CFG80211_SME_CONNECTED:
|
||||
cfg80211_disconnected(ndev, WLAN_STATUS_UNSPECIFIED_FAILURE,
|
||||
NULL, 0, GFP_KERNEL);
|
||||
break;
|
||||
case CFG80211_SME_CONNECTING:
|
||||
cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
|
||||
WLAN_STATUS_UNSPECIFIED_FAILURE,
|
||||
GFP_KERNEL);
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++)
|
||||
wil_vring_fini_tx(wil, i);
|
||||
}
|
||||
|
||||
static void wil_disconnect_worker(struct work_struct *work)
|
||||
{
|
||||
struct wil6210_priv *wil = container_of(work,
|
||||
struct wil6210_priv, disconnect_worker);
|
||||
|
||||
_wil6210_disconnect(wil, NULL);
|
||||
}
|
||||
|
||||
static void wil_connect_timer_fn(ulong x)
|
||||
{
|
||||
struct wil6210_priv *wil = (void *)x;
|
||||
|
||||
wil_dbg(wil, "Connect timeout\n");
|
||||
|
||||
/* reschedule to thread context - disconnect won't
|
||||
* run from atomic context
|
||||
*/
|
||||
schedule_work(&wil->disconnect_worker);
|
||||
}
|
||||
|
||||
int wil_priv_init(struct wil6210_priv *wil)
|
||||
{
|
||||
wil_dbg(wil, "%s()\n", __func__);
|
||||
|
||||
mutex_init(&wil->mutex);
|
||||
mutex_init(&wil->wmi_mutex);
|
||||
|
||||
init_completion(&wil->wmi_ready);
|
||||
|
||||
wil->pending_connect_cid = -1;
|
||||
setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil);
|
||||
|
||||
INIT_WORK(&wil->wmi_connect_worker, wmi_connect_worker);
|
||||
INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker);
|
||||
INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
|
||||
|
||||
INIT_LIST_HEAD(&wil->pending_wmi_ev);
|
||||
spin_lock_init(&wil->wmi_ev_lock);
|
||||
|
||||
wil->wmi_wq = create_singlethread_workqueue(WIL_NAME"_wmi");
|
||||
if (!wil->wmi_wq)
|
||||
return -EAGAIN;
|
||||
|
||||
wil->wmi_wq_conn = create_singlethread_workqueue(WIL_NAME"_connect");
|
||||
if (!wil->wmi_wq_conn) {
|
||||
destroy_workqueue(wil->wmi_wq);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/* make shadow copy of registers that should not change on run time */
|
||||
wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX,
|
||||
sizeof(struct wil6210_mbox_ctl));
|
||||
wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx);
|
||||
wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wil6210_disconnect(struct wil6210_priv *wil, void *bssid)
|
||||
{
|
||||
del_timer_sync(&wil->connect_timer);
|
||||
_wil6210_disconnect(wil, bssid);
|
||||
}
|
||||
|
||||
void wil_priv_deinit(struct wil6210_priv *wil)
|
||||
{
|
||||
cancel_work_sync(&wil->disconnect_worker);
|
||||
wil6210_disconnect(wil, NULL);
|
||||
wmi_event_flush(wil);
|
||||
destroy_workqueue(wil->wmi_wq_conn);
|
||||
destroy_workqueue(wil->wmi_wq);
|
||||
}
|
||||
|
||||
static void wil_target_reset(struct wil6210_priv *wil)
|
||||
{
|
||||
wil_dbg(wil, "Resetting...\n");
|
||||
|
||||
/* register write */
|
||||
#define W(a, v) iowrite32(v, wil->csr + HOSTADDR(a))
|
||||
/* register set = read, OR, write */
|
||||
#define S(a, v) iowrite32(ioread32(wil->csr + HOSTADDR(a)) | v, \
|
||||
wil->csr + HOSTADDR(a))
|
||||
|
||||
/* hpal_perst_from_pad_src_n_mask */
|
||||
S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(6));
|
||||
/* car_perst_rst_src_n_mask */
|
||||
S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(7));
|
||||
|
||||
W(RGF_USER_MAC_CPU_0, BIT(1)); /* mac_cpu_man_rst */
|
||||
W(RGF_USER_USER_CPU_0, BIT(1)); /* user_cpu_man_rst */
|
||||
|
||||
msleep(100);
|
||||
|
||||
W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000);
|
||||
W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F);
|
||||
W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000170);
|
||||
W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FC00);
|
||||
|
||||
msleep(100);
|
||||
|
||||
W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0);
|
||||
W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0);
|
||||
W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0);
|
||||
W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
|
||||
|
||||
W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001);
|
||||
W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080);
|
||||
W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
|
||||
|
||||
msleep(2000);
|
||||
|
||||
W(RGF_USER_USER_CPU_0, BIT(0)); /* user_cpu_man_de_rst */
|
||||
|
||||
msleep(2000);
|
||||
|
||||
wil_dbg(wil, "Reset completed\n");
|
||||
|
||||
#undef W
|
||||
#undef S
|
||||
}
|
||||
|
||||
void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
|
||||
{
|
||||
le32_to_cpus(&r->base);
|
||||
le16_to_cpus(&r->entry_size);
|
||||
le16_to_cpus(&r->size);
|
||||
le32_to_cpus(&r->tail);
|
||||
le32_to_cpus(&r->head);
|
||||
}
|
||||
|
||||
static int wil_wait_for_fw_ready(struct wil6210_priv *wil)
|
||||
{
|
||||
ulong to = msecs_to_jiffies(1000);
|
||||
ulong left = wait_for_completion_timeout(&wil->wmi_ready, to);
|
||||
if (0 == left) {
|
||||
wil_err(wil, "Firmware not ready\n");
|
||||
return -ETIME;
|
||||
} else {
|
||||
wil_dbg(wil, "FW ready after %d ms\n",
|
||||
jiffies_to_msecs(to-left));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We reset all the structures, and we reset the UMAC.
|
||||
* After calling this routine, you're expected to reload
|
||||
* the firmware.
|
||||
*/
|
||||
int wil_reset(struct wil6210_priv *wil)
|
||||
{
|
||||
int rc;
|
||||
|
||||
cancel_work_sync(&wil->disconnect_worker);
|
||||
wil6210_disconnect(wil, NULL);
|
||||
|
||||
wmi_event_flush(wil);
|
||||
|
||||
flush_workqueue(wil->wmi_wq);
|
||||
flush_workqueue(wil->wmi_wq_conn);
|
||||
|
||||
wil6210_disable_irq(wil);
|
||||
wil->status = 0;
|
||||
|
||||
/* TODO: put MAC in reset */
|
||||
wil_target_reset(wil);
|
||||
|
||||
/* init after reset */
|
||||
wil->pending_connect_cid = -1;
|
||||
INIT_COMPLETION(wil->wmi_ready);
|
||||
|
||||
/* make shadow copy of registers that should not change on run time */
|
||||
wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX,
|
||||
sizeof(struct wil6210_mbox_ctl));
|
||||
wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx);
|
||||
wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx);
|
||||
|
||||
/* TODO: release MAC reset */
|
||||
wil6210_enable_irq(wil);
|
||||
|
||||
/* we just started MAC, wait for FW ready */
|
||||
rc = wil_wait_for_fw_ready(wil);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
void wil_link_on(struct wil6210_priv *wil)
|
||||
{
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
|
||||
wil_dbg(wil, "%s()\n", __func__);
|
||||
|
||||
netif_carrier_on(ndev);
|
||||
netif_tx_wake_all_queues(ndev);
|
||||
}
|
||||
|
||||
void wil_link_off(struct wil6210_priv *wil)
|
||||
{
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
|
||||
wil_dbg(wil, "%s()\n", __func__);
|
||||
|
||||
netif_tx_stop_all_queues(ndev);
|
||||
netif_carrier_off(ndev);
|
||||
}
|
||||
|
||||
static int __wil_up(struct wil6210_priv *wil)
|
||||
{
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct wireless_dev *wdev = wil->wdev;
|
||||
struct ieee80211_channel *channel = wdev->preset_chandef.chan;
|
||||
int rc;
|
||||
int bi;
|
||||
u16 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype);
|
||||
|
||||
rc = wil_reset(wil);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* FIXME Firmware works now in PBSS mode(ToDS=0, FromDS=0) */
|
||||
wmi_nettype = wil_iftype_nl2wmi(NL80211_IFTYPE_ADHOC);
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
wil_dbg(wil, "type: STATION\n");
|
||||
bi = 0;
|
||||
ndev->type = ARPHRD_ETHER;
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
wil_dbg(wil, "type: AP\n");
|
||||
bi = 100;
|
||||
ndev->type = ARPHRD_ETHER;
|
||||
break;
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
wil_dbg(wil, "type: P2P_CLIENT\n");
|
||||
bi = 0;
|
||||
ndev->type = ARPHRD_ETHER;
|
||||
break;
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
wil_dbg(wil, "type: P2P_GO\n");
|
||||
bi = 100;
|
||||
ndev->type = ARPHRD_ETHER;
|
||||
break;
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
wil_dbg(wil, "type: Monitor\n");
|
||||
bi = 0;
|
||||
ndev->type = ARPHRD_IEEE80211_RADIOTAP;
|
||||
/* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_RADIOTAP ? */
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* Apply profile in the following order: */
|
||||
/* SSID and channel for the AP */
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
if (wdev->ssid_len == 0) {
|
||||
wil_err(wil, "SSID not set\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
wmi_set_ssid(wil, wdev->ssid_len, wdev->ssid);
|
||||
if (channel)
|
||||
wmi_set_channel(wil, channel->hw_value);
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
||||
/* MAC address - pre-requisite for other commands */
|
||||
wmi_set_mac_address(wil, ndev->dev_addr);
|
||||
|
||||
/* Set up beaconing if required. */
|
||||
rc = wmi_set_bcon(wil, bi, wmi_nettype);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Rx VRING. After MAC and beacon */
|
||||
wil_rx_init(wil);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wil_up(struct wil6210_priv *wil)
|
||||
{
|
||||
int rc;
|
||||
|
||||
mutex_lock(&wil->mutex);
|
||||
rc = __wil_up(wil);
|
||||
mutex_unlock(&wil->mutex);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __wil_down(struct wil6210_priv *wil)
|
||||
{
|
||||
if (wil->scan_request) {
|
||||
cfg80211_scan_done(wil->scan_request, true);
|
||||
wil->scan_request = NULL;
|
||||
}
|
||||
|
||||
wil6210_disconnect(wil, NULL);
|
||||
wil_rx_fini(wil);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wil_down(struct wil6210_priv *wil)
|
||||
{
|
||||
int rc;
|
||||
|
||||
mutex_lock(&wil->mutex);
|
||||
rc = __wil_down(wil);
|
||||
mutex_unlock(&wil->mutex);
|
||||
|
||||
return rc;
|
||||
}
|
157
drivers/net/wireless/ath/wil6210/netdev.c
Normal file
157
drivers/net/wireless/ath/wil6210/netdev.c
Normal file
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Qualcomm Atheros, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "wil6210.h"
|
||||
|
||||
static int wil_open(struct net_device *ndev)
|
||||
{
|
||||
struct wil6210_priv *wil = ndev_to_wil(ndev);
|
||||
|
||||
return wil_up(wil);
|
||||
}
|
||||
|
||||
static int wil_stop(struct net_device *ndev)
|
||||
{
|
||||
struct wil6210_priv *wil = ndev_to_wil(ndev);
|
||||
|
||||
return wil_down(wil);
|
||||
}
|
||||
|
||||
/*
|
||||
* AC to queue mapping
|
||||
*
|
||||
* AC_VO -> queue 3
|
||||
* AC_VI -> queue 2
|
||||
* AC_BE -> queue 1
|
||||
* AC_BK -> queue 0
|
||||
*/
|
||||
static u16 wil_select_queue(struct net_device *ndev, struct sk_buff *skb)
|
||||
{
|
||||
static const u16 wil_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 };
|
||||
struct wil6210_priv *wil = ndev_to_wil(ndev);
|
||||
u16 rc;
|
||||
|
||||
skb->priority = cfg80211_classify8021d(skb);
|
||||
|
||||
rc = wil_1d_to_queue[skb->priority];
|
||||
|
||||
wil_dbg_TXRX(wil, "%s() %d -> %d\n", __func__, (int)skb->priority,
|
||||
(int)rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const struct net_device_ops wil_netdev_ops = {
|
||||
.ndo_open = wil_open,
|
||||
.ndo_stop = wil_stop,
|
||||
.ndo_start_xmit = wil_start_xmit,
|
||||
.ndo_select_queue = wil_select_queue,
|
||||
.ndo_set_mac_address = eth_mac_addr,
|
||||
.ndo_validate_addr = eth_validate_addr,
|
||||
};
|
||||
|
||||
void *wil_if_alloc(struct device *dev, void __iomem *csr)
|
||||
{
|
||||
struct net_device *ndev;
|
||||
struct wireless_dev *wdev;
|
||||
struct wil6210_priv *wil;
|
||||
struct ieee80211_channel *ch;
|
||||
int rc = 0;
|
||||
|
||||
wdev = wil_cfg80211_init(dev);
|
||||
if (IS_ERR(wdev)) {
|
||||
dev_err(dev, "wil_cfg80211_init failed\n");
|
||||
return wdev;
|
||||
}
|
||||
|
||||
wil = wdev_to_wil(wdev);
|
||||
wil->csr = csr;
|
||||
wil->wdev = wdev;
|
||||
|
||||
rc = wil_priv_init(wil);
|
||||
if (rc) {
|
||||
dev_err(dev, "wil_priv_init failed\n");
|
||||
goto out_wdev;
|
||||
}
|
||||
|
||||
wdev->iftype = NL80211_IFTYPE_STATION; /* TODO */
|
||||
/* default monitor channel */
|
||||
ch = wdev->wiphy->bands[IEEE80211_BAND_60GHZ]->channels;
|
||||
cfg80211_chandef_create(&wdev->preset_chandef, ch, NL80211_CHAN_NO_HT);
|
||||
|
||||
ndev = alloc_netdev_mqs(0, "wlan%d", ether_setup, WIL6210_TX_QUEUES, 1);
|
||||
if (!ndev) {
|
||||
dev_err(dev, "alloc_netdev_mqs failed\n");
|
||||
rc = -ENOMEM;
|
||||
goto out_priv;
|
||||
}
|
||||
|
||||
ndev->netdev_ops = &wil_netdev_ops;
|
||||
ndev->ieee80211_ptr = wdev;
|
||||
SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
|
||||
wdev->netdev = ndev;
|
||||
|
||||
wil_link_off(wil);
|
||||
|
||||
return wil;
|
||||
|
||||
out_priv:
|
||||
wil_priv_deinit(wil);
|
||||
|
||||
out_wdev:
|
||||
wil_wdev_free(wil);
|
||||
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
void wil_if_free(struct wil6210_priv *wil)
|
||||
{
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
if (!ndev)
|
||||
return;
|
||||
|
||||
free_netdev(ndev);
|
||||
wil_priv_deinit(wil);
|
||||
wil_wdev_free(wil);
|
||||
}
|
||||
|
||||
int wil_if_add(struct wil6210_priv *wil)
|
||||
{
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
int rc;
|
||||
|
||||
rc = register_netdev(ndev);
|
||||
if (rc < 0) {
|
||||
dev_err(&ndev->dev, "Failed to register netdev: %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
wil_link_off(wil);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wil_if_remove(struct wil6210_priv *wil)
|
||||
{
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
|
||||
unregister_netdev(ndev);
|
||||
}
|
223
drivers/net/wireless/ath/wil6210/pcie_bus.c
Normal file
223
drivers/net/wireless/ath/wil6210/pcie_bus.c
Normal file
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Qualcomm Atheros, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/moduleparam.h>
|
||||
|
||||
#include "wil6210.h"
|
||||
|
||||
static int use_msi = 1;
|
||||
module_param(use_msi, int, S_IRUGO);
|
||||
MODULE_PARM_DESC(use_msi,
|
||||
" Use MSI interrupt: "
|
||||
"0 - don't, 1 - (default) - single, or 3");
|
||||
|
||||
/* Bus ops */
|
||||
static int wil_if_pcie_enable(struct wil6210_priv *wil)
|
||||
{
|
||||
struct pci_dev *pdev = wil->pdev;
|
||||
int rc;
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
/*
|
||||
* how many MSI interrupts to request?
|
||||
*/
|
||||
switch (use_msi) {
|
||||
case 3:
|
||||
case 1:
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
wil_err(wil, "Invalid use_msi=%d, default to 1\n",
|
||||
use_msi);
|
||||
use_msi = 1;
|
||||
}
|
||||
wil->n_msi = use_msi;
|
||||
if (wil->n_msi) {
|
||||
wil_dbg(wil, "Setup %d MSI interrupts\n", use_msi);
|
||||
rc = pci_enable_msi_block(pdev, wil->n_msi);
|
||||
if (rc && (wil->n_msi == 3)) {
|
||||
wil_err(wil, "3 MSI mode failed, try 1 MSI\n");
|
||||
wil->n_msi = 1;
|
||||
rc = pci_enable_msi_block(pdev, wil->n_msi);
|
||||
}
|
||||
if (rc) {
|
||||
wil_err(wil, "pci_enable_msi failed, use INTx\n");
|
||||
wil->n_msi = 0;
|
||||
}
|
||||
} else {
|
||||
wil_dbg(wil, "MSI interrupts disabled, use INTx\n");
|
||||
}
|
||||
|
||||
rc = wil6210_init_irq(wil, pdev->irq);
|
||||
if (rc)
|
||||
goto stop_master;
|
||||
|
||||
/* need reset here to obtain MAC */
|
||||
rc = wil_reset(wil);
|
||||
if (rc)
|
||||
goto release_irq;
|
||||
|
||||
return 0;
|
||||
|
||||
release_irq:
|
||||
wil6210_fini_irq(wil, pdev->irq);
|
||||
/* safe to call if no MSI */
|
||||
pci_disable_msi(pdev);
|
||||
stop_master:
|
||||
pci_clear_master(pdev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int wil_if_pcie_disable(struct wil6210_priv *wil)
|
||||
{
|
||||
struct pci_dev *pdev = wil->pdev;
|
||||
|
||||
pci_clear_master(pdev);
|
||||
/* disable and release IRQ */
|
||||
wil6210_fini_irq(wil, pdev->irq);
|
||||
/* safe to call if no MSI */
|
||||
pci_disable_msi(pdev);
|
||||
/* TODO: disable HW */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
{
|
||||
struct wil6210_priv *wil;
|
||||
struct device *dev = &pdev->dev;
|
||||
void __iomem *csr;
|
||||
int rc;
|
||||
|
||||
/* check HW */
|
||||
dev_info(&pdev->dev, WIL_NAME " device found [%04x:%04x] (rev %x)\n",
|
||||
(int)pdev->vendor, (int)pdev->device, (int)pdev->revision);
|
||||
|
||||
if (pci_resource_len(pdev, 0) != WIL6210_MEM_SIZE) {
|
||||
dev_err(&pdev->dev, "Not " WIL_NAME "? "
|
||||
"BAR0 size is %lu while expecting %lu\n",
|
||||
(ulong)pci_resource_len(pdev, 0), WIL6210_MEM_SIZE);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
rc = pci_enable_device(pdev);
|
||||
if (rc) {
|
||||
dev_err(&pdev->dev, "pci_enable_device failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
/* rollback to err_disable_pdev */
|
||||
|
||||
rc = pci_request_region(pdev, 0, WIL_NAME);
|
||||
if (rc) {
|
||||
dev_err(&pdev->dev, "pci_request_region failed\n");
|
||||
goto err_disable_pdev;
|
||||
}
|
||||
/* rollback to err_release_reg */
|
||||
|
||||
csr = pci_ioremap_bar(pdev, 0);
|
||||
if (!csr) {
|
||||
dev_err(&pdev->dev, "pci_ioremap_bar failed\n");
|
||||
rc = -ENODEV;
|
||||
goto err_release_reg;
|
||||
}
|
||||
/* rollback to err_iounmap */
|
||||
dev_info(&pdev->dev, "CSR at %pR -> %p\n", &pdev->resource[0], csr);
|
||||
|
||||
wil = wil_if_alloc(dev, csr);
|
||||
if (IS_ERR(wil)) {
|
||||
rc = (int)PTR_ERR(wil);
|
||||
dev_err(dev, "wil_if_alloc failed: %d\n", rc);
|
||||
goto err_iounmap;
|
||||
}
|
||||
/* rollback to if_free */
|
||||
|
||||
pci_set_drvdata(pdev, wil);
|
||||
wil->pdev = pdev;
|
||||
|
||||
/* FW should raise IRQ when ready */
|
||||
rc = wil_if_pcie_enable(wil);
|
||||
if (rc) {
|
||||
wil_err(wil, "Enable device failed\n");
|
||||
goto if_free;
|
||||
}
|
||||
/* rollback to bus_disable */
|
||||
|
||||
rc = wil_if_add(wil);
|
||||
if (rc) {
|
||||
wil_err(wil, "wil_if_add failed: %d\n", rc);
|
||||
goto bus_disable;
|
||||
}
|
||||
|
||||
wil6210_debugfs_init(wil);
|
||||
|
||||
/* check FW is alive */
|
||||
wmi_echo(wil);
|
||||
|
||||
return 0;
|
||||
|
||||
bus_disable:
|
||||
wil_if_pcie_disable(wil);
|
||||
if_free:
|
||||
wil_if_free(wil);
|
||||
err_iounmap:
|
||||
pci_iounmap(pdev, csr);
|
||||
err_release_reg:
|
||||
pci_release_region(pdev, 0);
|
||||
err_disable_pdev:
|
||||
pci_disable_device(pdev);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void wil_pcie_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct wil6210_priv *wil = pci_get_drvdata(pdev);
|
||||
|
||||
wil6210_debugfs_remove(wil);
|
||||
wil_if_pcie_disable(wil);
|
||||
wil_if_remove(wil);
|
||||
wil_if_free(wil);
|
||||
pci_iounmap(pdev, wil->csr);
|
||||
pci_release_region(pdev, 0);
|
||||
pci_disable_device(pdev);
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
}
|
||||
|
||||
static DEFINE_PCI_DEVICE_TABLE(wil6210_pcie_ids) = {
|
||||
{ PCI_DEVICE(0x1ae9, 0x0301) },
|
||||
{ /* end: all zeroes */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids);
|
||||
|
||||
static struct pci_driver wil6210_driver = {
|
||||
.probe = wil_pcie_probe,
|
||||
.remove = wil_pcie_remove,
|
||||
.id_table = wil6210_pcie_ids,
|
||||
.name = WIL_NAME,
|
||||
};
|
||||
|
||||
module_pci_driver(wil6210_driver);
|
||||
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
MODULE_AUTHOR("Qualcomm Atheros <wil6210@qca.qualcomm.com>");
|
||||
MODULE_DESCRIPTION("Driver for 60g WiFi WIL6210 card");
|
871
drivers/net/wireless/ath/wil6210/txrx.c
Normal file
871
drivers/net/wireless/ath/wil6210/txrx.c
Normal file
|
@ -0,0 +1,871 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Qualcomm Atheros, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/hardirq.h>
|
||||
#include <net/ieee80211_radiotap.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/moduleparam.h>
|
||||
|
||||
#include "wil6210.h"
|
||||
#include "wmi.h"
|
||||
#include "txrx.h"
|
||||
|
||||
static bool rtap_include_phy_info;
|
||||
module_param(rtap_include_phy_info, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(rtap_include_phy_info,
|
||||
" Include PHY info in the radiotap header, default - no");
|
||||
|
||||
static inline int wil_vring_is_empty(struct vring *vring)
|
||||
{
|
||||
return vring->swhead == vring->swtail;
|
||||
}
|
||||
|
||||
static inline u32 wil_vring_next_tail(struct vring *vring)
|
||||
{
|
||||
return (vring->swtail + 1) % vring->size;
|
||||
}
|
||||
|
||||
static inline void wil_vring_advance_head(struct vring *vring, int n)
|
||||
{
|
||||
vring->swhead = (vring->swhead + n) % vring->size;
|
||||
}
|
||||
|
||||
static inline int wil_vring_is_full(struct vring *vring)
|
||||
{
|
||||
return wil_vring_next_tail(vring) == vring->swhead;
|
||||
}
|
||||
/*
|
||||
* Available space in Tx Vring
|
||||
*/
|
||||
static inline int wil_vring_avail_tx(struct vring *vring)
|
||||
{
|
||||
u32 swhead = vring->swhead;
|
||||
u32 swtail = vring->swtail;
|
||||
int used = (vring->size + swhead - swtail) % vring->size;
|
||||
|
||||
return vring->size - used - 1;
|
||||
}
|
||||
|
||||
static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring)
|
||||
{
|
||||
struct device *dev = wil_to_dev(wil);
|
||||
size_t sz = vring->size * sizeof(vring->va[0]);
|
||||
uint i;
|
||||
|
||||
BUILD_BUG_ON(sizeof(vring->va[0]) != 32);
|
||||
|
||||
vring->swhead = 0;
|
||||
vring->swtail = 0;
|
||||
vring->ctx = kzalloc(vring->size * sizeof(vring->ctx[0]), GFP_KERNEL);
|
||||
if (!vring->ctx) {
|
||||
wil_err(wil, "vring_alloc [%d] failed to alloc ctx mem\n",
|
||||
vring->size);
|
||||
vring->va = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
/*
|
||||
* vring->va should be aligned on its size rounded up to power of 2
|
||||
* This is granted by the dma_alloc_coherent
|
||||
*/
|
||||
vring->va = dma_alloc_coherent(dev, sz, &vring->pa, GFP_KERNEL);
|
||||
if (!vring->va) {
|
||||
wil_err(wil, "vring_alloc [%d] failed to alloc DMA mem\n",
|
||||
vring->size);
|
||||
kfree(vring->ctx);
|
||||
vring->ctx = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
/* initially, all descriptors are SW owned
|
||||
* For Tx and Rx, ownership bit is at the same location, thus
|
||||
* we can use any
|
||||
*/
|
||||
for (i = 0; i < vring->size; i++) {
|
||||
volatile struct vring_tx_desc *d = &(vring->va[i].tx);
|
||||
d->dma.status = TX_DMA_STATUS_DU;
|
||||
}
|
||||
|
||||
wil_dbg(wil, "vring[%d] 0x%p:0x%016llx 0x%p\n", vring->size,
|
||||
vring->va, (unsigned long long)vring->pa, vring->ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring,
|
||||
int tx)
|
||||
{
|
||||
struct device *dev = wil_to_dev(wil);
|
||||
size_t sz = vring->size * sizeof(vring->va[0]);
|
||||
|
||||
while (!wil_vring_is_empty(vring)) {
|
||||
if (tx) {
|
||||
volatile struct vring_tx_desc *d =
|
||||
&vring->va[vring->swtail].tx;
|
||||
dma_addr_t pa = d->dma.addr_low |
|
||||
((u64)d->dma.addr_high << 32);
|
||||
struct sk_buff *skb = vring->ctx[vring->swtail];
|
||||
if (skb) {
|
||||
dma_unmap_single(dev, pa, d->dma.length,
|
||||
DMA_TO_DEVICE);
|
||||
dev_kfree_skb_any(skb);
|
||||
vring->ctx[vring->swtail] = NULL;
|
||||
} else {
|
||||
dma_unmap_page(dev, pa, d->dma.length,
|
||||
DMA_TO_DEVICE);
|
||||
}
|
||||
vring->swtail = wil_vring_next_tail(vring);
|
||||
} else { /* rx */
|
||||
volatile struct vring_rx_desc *d =
|
||||
&vring->va[vring->swtail].rx;
|
||||
dma_addr_t pa = d->dma.addr_low |
|
||||
((u64)d->dma.addr_high << 32);
|
||||
struct sk_buff *skb = vring->ctx[vring->swhead];
|
||||
dma_unmap_single(dev, pa, d->dma.length,
|
||||
DMA_FROM_DEVICE);
|
||||
kfree_skb(skb);
|
||||
wil_vring_advance_head(vring, 1);
|
||||
}
|
||||
}
|
||||
dma_free_coherent(dev, sz, (void *)vring->va, vring->pa);
|
||||
kfree(vring->ctx);
|
||||
vring->pa = 0;
|
||||
vring->va = NULL;
|
||||
vring->ctx = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate one skb for Rx VRING
|
||||
*
|
||||
* Safe to call from IRQ
|
||||
*/
|
||||
static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring,
|
||||
u32 i, int headroom)
|
||||
{
|
||||
struct device *dev = wil_to_dev(wil);
|
||||
unsigned int sz = RX_BUF_LEN;
|
||||
volatile struct vring_rx_desc *d = &(vring->va[i].rx);
|
||||
dma_addr_t pa;
|
||||
|
||||
/* TODO align */
|
||||
struct sk_buff *skb = dev_alloc_skb(sz + headroom);
|
||||
if (unlikely(!skb))
|
||||
return -ENOMEM;
|
||||
|
||||
skb_reserve(skb, headroom);
|
||||
skb_put(skb, sz);
|
||||
|
||||
pa = dma_map_single(dev, skb->data, skb->len, DMA_FROM_DEVICE);
|
||||
if (unlikely(dma_mapping_error(dev, pa))) {
|
||||
kfree_skb(skb);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
d->dma.d0 = BIT(9) | RX_DMA_D0_CMD_DMA_IT;
|
||||
d->dma.addr_low = lower_32_bits(pa);
|
||||
d->dma.addr_high = (u16)upper_32_bits(pa);
|
||||
/* ip_length don't care */
|
||||
/* b11 don't care */
|
||||
/* error don't care */
|
||||
d->dma.status = 0; /* BIT(0) should be 0 for HW_OWNED */
|
||||
d->dma.length = sz;
|
||||
vring->ctx[i] = skb;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds radiotap header
|
||||
*
|
||||
* Any error indicated as "Bad FCS"
|
||||
*
|
||||
* Vendor data for 04:ce:14-1 (Wilocity-1) consists of:
|
||||
* - Rx descriptor: 32 bytes
|
||||
* - Phy info
|
||||
*/
|
||||
static void wil_rx_add_radiotap_header(struct wil6210_priv *wil,
|
||||
struct sk_buff *skb,
|
||||
volatile struct vring_rx_desc *d)
|
||||
{
|
||||
struct wireless_dev *wdev = wil->wdev;
|
||||
struct wil6210_rtap {
|
||||
struct ieee80211_radiotap_header rthdr;
|
||||
/* fields should be in the order of bits in rthdr.it_present */
|
||||
/* flags */
|
||||
u8 flags;
|
||||
/* channel */
|
||||
__le16 chnl_freq __aligned(2);
|
||||
__le16 chnl_flags;
|
||||
/* MCS */
|
||||
u8 mcs_present;
|
||||
u8 mcs_flags;
|
||||
u8 mcs_index;
|
||||
} __packed;
|
||||
struct wil6210_rtap_vendor {
|
||||
struct wil6210_rtap rtap;
|
||||
/* vendor */
|
||||
u8 vendor_oui[3] __aligned(2);
|
||||
u8 vendor_ns;
|
||||
__le16 vendor_skip;
|
||||
u8 vendor_data[0];
|
||||
} __packed;
|
||||
struct wil6210_rtap_vendor *rtap_vendor;
|
||||
int rtap_len = sizeof(struct wil6210_rtap);
|
||||
int phy_length = 0; /* phy info header size, bytes */
|
||||
static char phy_data[128];
|
||||
struct ieee80211_channel *ch = wdev->preset_chandef.chan;
|
||||
|
||||
if (rtap_include_phy_info) {
|
||||
rtap_len = sizeof(*rtap_vendor) + sizeof(*d);
|
||||
/* calculate additional length */
|
||||
if (d->dma.status & RX_DMA_STATUS_PHY_INFO) {
|
||||
/**
|
||||
* PHY info starts from 8-byte boundary
|
||||
* there are 8-byte lines, last line may be partially
|
||||
* written (HW bug), thus FW configures for last line
|
||||
* to be excessive. Driver skips this last line.
|
||||
*/
|
||||
int len = min_t(int, 8 + sizeof(phy_data),
|
||||
wil_rxdesc_phy_length(d));
|
||||
if (len > 8) {
|
||||
void *p = skb_tail_pointer(skb);
|
||||
void *pa = PTR_ALIGN(p, 8);
|
||||
if (skb_tailroom(skb) >= len + (pa - p)) {
|
||||
phy_length = len - 8;
|
||||
memcpy(phy_data, pa, phy_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
rtap_len += phy_length;
|
||||
}
|
||||
|
||||
if (skb_headroom(skb) < rtap_len &&
|
||||
pskb_expand_head(skb, rtap_len, 0, GFP_ATOMIC)) {
|
||||
wil_err(wil, "Unable to expand headrom to %d\n", rtap_len);
|
||||
return;
|
||||
}
|
||||
|
||||
rtap_vendor = (void *)skb_push(skb, rtap_len);
|
||||
memset(rtap_vendor, 0, rtap_len);
|
||||
|
||||
rtap_vendor->rtap.rthdr.it_version = PKTHDR_RADIOTAP_VERSION;
|
||||
rtap_vendor->rtap.rthdr.it_len = cpu_to_le16(rtap_len);
|
||||
rtap_vendor->rtap.rthdr.it_present = cpu_to_le32(
|
||||
(1 << IEEE80211_RADIOTAP_FLAGS) |
|
||||
(1 << IEEE80211_RADIOTAP_CHANNEL) |
|
||||
(1 << IEEE80211_RADIOTAP_MCS));
|
||||
if (d->dma.status & RX_DMA_STATUS_ERROR)
|
||||
rtap_vendor->rtap.flags |= IEEE80211_RADIOTAP_F_BADFCS;
|
||||
|
||||
rtap_vendor->rtap.chnl_freq = cpu_to_le16(ch ? ch->center_freq : 58320);
|
||||
rtap_vendor->rtap.chnl_flags = cpu_to_le16(0);
|
||||
|
||||
rtap_vendor->rtap.mcs_present = IEEE80211_RADIOTAP_MCS_HAVE_MCS;
|
||||
rtap_vendor->rtap.mcs_flags = 0;
|
||||
rtap_vendor->rtap.mcs_index = wil_rxdesc_mcs(d);
|
||||
|
||||
if (rtap_include_phy_info) {
|
||||
rtap_vendor->rtap.rthdr.it_present |= cpu_to_le32(1 <<
|
||||
IEEE80211_RADIOTAP_VENDOR_NAMESPACE);
|
||||
/* OUI for Wilocity 04:ce:14 */
|
||||
rtap_vendor->vendor_oui[0] = 0x04;
|
||||
rtap_vendor->vendor_oui[1] = 0xce;
|
||||
rtap_vendor->vendor_oui[2] = 0x14;
|
||||
rtap_vendor->vendor_ns = 1;
|
||||
/* Rx descriptor + PHY data */
|
||||
rtap_vendor->vendor_skip = cpu_to_le16(sizeof(*d) +
|
||||
phy_length);
|
||||
memcpy(rtap_vendor->vendor_data, (void *)d, sizeof(*d));
|
||||
memcpy(rtap_vendor->vendor_data + sizeof(*d), phy_data,
|
||||
phy_length);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Fast swap in place between 2 registers
|
||||
*/
|
||||
static void wil_swap_u16(u16 *a, u16 *b)
|
||||
{
|
||||
*a ^= *b;
|
||||
*b ^= *a;
|
||||
*a ^= *b;
|
||||
}
|
||||
|
||||
static void wil_swap_ethaddr(void *data)
|
||||
{
|
||||
struct ethhdr *eth = data;
|
||||
u16 *s = (u16 *)eth->h_source;
|
||||
u16 *d = (u16 *)eth->h_dest;
|
||||
|
||||
wil_swap_u16(s++, d++);
|
||||
wil_swap_u16(s++, d++);
|
||||
wil_swap_u16(s, d);
|
||||
}
|
||||
|
||||
/**
|
||||
* reap 1 frame from @swhead
|
||||
*
|
||||
* Safe to call from IRQ
|
||||
*/
|
||||
static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
|
||||
struct vring *vring)
|
||||
{
|
||||
struct device *dev = wil_to_dev(wil);
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
volatile struct vring_rx_desc *d;
|
||||
struct sk_buff *skb;
|
||||
dma_addr_t pa;
|
||||
unsigned int sz = RX_BUF_LEN;
|
||||
u8 ftype;
|
||||
u8 ds_bits;
|
||||
|
||||
if (wil_vring_is_empty(vring))
|
||||
return NULL;
|
||||
|
||||
d = &(vring->va[vring->swhead].rx);
|
||||
if (!(d->dma.status & RX_DMA_STATUS_DU)) {
|
||||
/* it is not error, we just reached end of Rx done area */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32);
|
||||
skb = vring->ctx[vring->swhead];
|
||||
dma_unmap_single(dev, pa, sz, DMA_FROM_DEVICE);
|
||||
skb_trim(skb, d->dma.length);
|
||||
|
||||
wil->stats.last_mcs_rx = wil_rxdesc_mcs(d);
|
||||
|
||||
/* use radiotap header only if required */
|
||||
if (ndev->type == ARPHRD_IEEE80211_RADIOTAP)
|
||||
wil_rx_add_radiotap_header(wil, skb, d);
|
||||
|
||||
wil_dbg_TXRX(wil, "Rx[%3d] : %d bytes\n", vring->swhead, d->dma.length);
|
||||
wil_hex_dump_TXRX("Rx ", DUMP_PREFIX_NONE, 32, 4,
|
||||
(const void *)d, sizeof(*d), false);
|
||||
|
||||
wil_vring_advance_head(vring, 1);
|
||||
|
||||
/* no extra checks if in sniffer mode */
|
||||
if (ndev->type != ARPHRD_ETHER)
|
||||
return skb;
|
||||
/*
|
||||
* Non-data frames may be delivered through Rx DMA channel (ex: BAR)
|
||||
* Driver should recognize it by frame type, that is found
|
||||
* in Rx descriptor. If type is not data, it is 802.11 frame as is
|
||||
*/
|
||||
ftype = wil_rxdesc_ftype(d) << 2;
|
||||
if (ftype != IEEE80211_FTYPE_DATA) {
|
||||
wil_dbg_TXRX(wil, "Non-data frame ftype 0x%08x\n", ftype);
|
||||
/* TODO: process it */
|
||||
kfree_skb(skb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (skb->len < ETH_HLEN) {
|
||||
wil_err(wil, "Short frame, len = %d\n", skb->len);
|
||||
/* TODO: process it (i.e. BAR) */
|
||||
kfree_skb(skb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ds_bits = wil_rxdesc_ds_bits(d);
|
||||
if (ds_bits == 1) {
|
||||
/*
|
||||
* HW bug - in ToDS mode, i.e. Rx on AP side,
|
||||
* addresses get swapped
|
||||
*/
|
||||
wil_swap_ethaddr(skb->data);
|
||||
}
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
/**
|
||||
* allocate and fill up to @count buffers in rx ring
|
||||
* buffers posted at @swtail
|
||||
*/
|
||||
static int wil_rx_refill(struct wil6210_priv *wil, int count)
|
||||
{
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct vring *v = &wil->vring_rx;
|
||||
u32 next_tail;
|
||||
int rc = 0;
|
||||
int headroom = ndev->type == ARPHRD_IEEE80211_RADIOTAP ?
|
||||
WIL6210_RTAP_SIZE : 0;
|
||||
|
||||
for (; next_tail = wil_vring_next_tail(v),
|
||||
(next_tail != v->swhead) && (count-- > 0);
|
||||
v->swtail = next_tail) {
|
||||
rc = wil_vring_alloc_skb(wil, v, v->swtail, headroom);
|
||||
if (rc) {
|
||||
wil_err(wil, "Error %d in wil_rx_refill[%d]\n",
|
||||
rc, v->swtail);
|
||||
break;
|
||||
}
|
||||
}
|
||||
iowrite32(v->swtail, wil->csr + HOSTADDR(v->hwtail));
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pass Rx packet to the netif. Update statistics.
|
||||
*/
|
||||
static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
|
||||
{
|
||||
int rc;
|
||||
unsigned int len = skb->len;
|
||||
|
||||
if (in_interrupt())
|
||||
rc = netif_rx(skb);
|
||||
else
|
||||
rc = netif_rx_ni(skb);
|
||||
|
||||
if (likely(rc == NET_RX_SUCCESS)) {
|
||||
ndev->stats.rx_packets++;
|
||||
ndev->stats.rx_bytes += len;
|
||||
|
||||
} else {
|
||||
ndev->stats.rx_dropped++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Proceed all completed skb's from Rx VRING
|
||||
*
|
||||
* Safe to call from IRQ
|
||||
*/
|
||||
void wil_rx_handle(struct wil6210_priv *wil)
|
||||
{
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct vring *v = &wil->vring_rx;
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (!v->va) {
|
||||
wil_err(wil, "Rx IRQ while Rx not yet initialized\n");
|
||||
return;
|
||||
}
|
||||
wil_dbg_TXRX(wil, "%s()\n", __func__);
|
||||
while (NULL != (skb = wil_vring_reap_rx(wil, v))) {
|
||||
wil_hex_dump_TXRX("Rx ", DUMP_PREFIX_OFFSET, 16, 1,
|
||||
skb->data, skb_headlen(skb), false);
|
||||
|
||||
skb_orphan(skb);
|
||||
|
||||
if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) {
|
||||
skb->dev = ndev;
|
||||
skb_reset_mac_header(skb);
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
skb->pkt_type = PACKET_OTHERHOST;
|
||||
skb->protocol = htons(ETH_P_802_2);
|
||||
|
||||
} else {
|
||||
skb->protocol = eth_type_trans(skb, ndev);
|
||||
}
|
||||
|
||||
wil_netif_rx_any(skb, ndev);
|
||||
}
|
||||
wil_rx_refill(wil, v->size);
|
||||
}
|
||||
|
||||
int wil_rx_init(struct wil6210_priv *wil)
|
||||
{
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct wireless_dev *wdev = wil->wdev;
|
||||
struct vring *vring = &wil->vring_rx;
|
||||
int rc;
|
||||
struct wmi_cfg_rx_chain_cmd cmd = {
|
||||
.action = WMI_RX_CHAIN_ADD,
|
||||
.rx_sw_ring = {
|
||||
.max_mpdu_size = cpu_to_le16(RX_BUF_LEN),
|
||||
},
|
||||
.mid = 0, /* TODO - what is it? */
|
||||
.decap_trans_type = WMI_DECAP_TYPE_802_3,
|
||||
};
|
||||
struct {
|
||||
struct wil6210_mbox_hdr_wmi wmi;
|
||||
struct wmi_cfg_rx_chain_done_event evt;
|
||||
} __packed evt;
|
||||
|
||||
vring->size = WIL6210_RX_RING_SIZE;
|
||||
rc = wil_vring_alloc(wil, vring);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
cmd.rx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);
|
||||
cmd.rx_sw_ring.ring_size = cpu_to_le16(vring->size);
|
||||
if (wdev->iftype == NL80211_IFTYPE_MONITOR) {
|
||||
struct ieee80211_channel *ch = wdev->preset_chandef.chan;
|
||||
|
||||
cmd.sniffer_cfg.mode = cpu_to_le32(WMI_SNIFFER_ON);
|
||||
if (ch)
|
||||
cmd.sniffer_cfg.channel = ch->hw_value - 1;
|
||||
cmd.sniffer_cfg.phy_info_mode =
|
||||
cpu_to_le32(ndev->type == ARPHRD_IEEE80211_RADIOTAP);
|
||||
cmd.sniffer_cfg.phy_support =
|
||||
cpu_to_le32((wil->monitor_flags & MONITOR_FLAG_CONTROL)
|
||||
? WMI_SNIFFER_CP : WMI_SNIFFER_DP);
|
||||
}
|
||||
/* typical time for secure PCP is 840ms */
|
||||
rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd),
|
||||
WMI_CFG_RX_CHAIN_DONE_EVENTID, &evt, sizeof(evt), 2000);
|
||||
if (rc)
|
||||
goto err_free;
|
||||
|
||||
vring->hwtail = le32_to_cpu(evt.evt.rx_ring_tail_ptr);
|
||||
|
||||
wil_dbg(wil, "Rx init: status %d tail 0x%08x\n",
|
||||
le32_to_cpu(evt.evt.status), vring->hwtail);
|
||||
|
||||
rc = wil_rx_refill(wil, vring->size);
|
||||
if (rc)
|
||||
goto err_free;
|
||||
|
||||
return 0;
|
||||
err_free:
|
||||
wil_vring_free(wil, vring, 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void wil_rx_fini(struct wil6210_priv *wil)
|
||||
{
|
||||
struct vring *vring = &wil->vring_rx;
|
||||
|
||||
if (vring->va) {
|
||||
int rc;
|
||||
struct wmi_cfg_rx_chain_cmd cmd = {
|
||||
.action = cpu_to_le32(WMI_RX_CHAIN_DEL),
|
||||
.rx_sw_ring = {
|
||||
.max_mpdu_size = cpu_to_le16(RX_BUF_LEN),
|
||||
},
|
||||
};
|
||||
struct {
|
||||
struct wil6210_mbox_hdr_wmi wmi;
|
||||
struct wmi_cfg_rx_chain_done_event cfg;
|
||||
} __packed wmi_rx_cfg_reply;
|
||||
|
||||
rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd),
|
||||
WMI_CFG_RX_CHAIN_DONE_EVENTID,
|
||||
&wmi_rx_cfg_reply, sizeof(wmi_rx_cfg_reply),
|
||||
100);
|
||||
wil_vring_free(wil, vring, 0);
|
||||
}
|
||||
}
|
||||
|
||||
int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
|
||||
int cid, int tid)
|
||||
{
|
||||
int rc;
|
||||
struct wmi_vring_cfg_cmd cmd = {
|
||||
.action = cpu_to_le32(WMI_VRING_CMD_ADD),
|
||||
.vring_cfg = {
|
||||
.tx_sw_ring = {
|
||||
.max_mpdu_size = cpu_to_le16(TX_BUF_LEN),
|
||||
},
|
||||
.ringid = id,
|
||||
.cidxtid = (cid & 0xf) | ((tid & 0xf) << 4),
|
||||
.encap_trans_type = WMI_VRING_ENC_TYPE_802_3,
|
||||
.mac_ctrl = 0,
|
||||
.to_resolution = 0,
|
||||
.agg_max_wsize = 16,
|
||||
.schd_params = {
|
||||
.priority = cpu_to_le16(0),
|
||||
.timeslot_us = cpu_to_le16(0xfff),
|
||||
},
|
||||
},
|
||||
};
|
||||
struct {
|
||||
struct wil6210_mbox_hdr_wmi wmi;
|
||||
struct wmi_vring_cfg_done_event cmd;
|
||||
} __packed reply;
|
||||
struct vring *vring = &wil->vring_tx[id];
|
||||
|
||||
if (vring->va) {
|
||||
wil_err(wil, "Tx ring [%d] already allocated\n", id);
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
vring->size = size;
|
||||
rc = wil_vring_alloc(wil, vring);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);
|
||||
cmd.vring_cfg.tx_sw_ring.ring_size = cpu_to_le16(vring->size);
|
||||
|
||||
rc = wmi_call(wil, WMI_VRING_CFG_CMDID, &cmd, sizeof(cmd),
|
||||
WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100);
|
||||
if (rc)
|
||||
goto out_free;
|
||||
|
||||
if (reply.cmd.status != WMI_VRING_CFG_SUCCESS) {
|
||||
wil_err(wil, "Tx config failed, status 0x%02x\n",
|
||||
reply.cmd.status);
|
||||
goto out_free;
|
||||
}
|
||||
vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr);
|
||||
|
||||
return 0;
|
||||
out_free:
|
||||
wil_vring_free(wil, vring, 1);
|
||||
out:
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
|
||||
{
|
||||
struct vring *vring = &wil->vring_tx[id];
|
||||
|
||||
if (!vring->va)
|
||||
return;
|
||||
|
||||
wil_vring_free(wil, vring, 1);
|
||||
}
|
||||
|
||||
static struct vring *wil_find_tx_vring(struct wil6210_priv *wil,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct vring *v = &wil->vring_tx[0];
|
||||
|
||||
if (v->va)
|
||||
return v;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int wil_tx_desc_map(volatile struct vring_tx_desc *d,
|
||||
dma_addr_t pa, u32 len)
|
||||
{
|
||||
d->dma.addr_low = lower_32_bits(pa);
|
||||
d->dma.addr_high = (u16)upper_32_bits(pa);
|
||||
d->dma.ip_length = 0;
|
||||
/* 0..6: mac_length; 7:ip_version 0-IP6 1-IP4*/
|
||||
d->dma.b11 = 0/*14 | BIT(7)*/;
|
||||
d->dma.error = 0;
|
||||
d->dma.status = 0; /* BIT(0) should be 0 for HW_OWNED */
|
||||
d->dma.length = len;
|
||||
d->dma.d0 = 0;
|
||||
d->mac.d[0] = 0;
|
||||
d->mac.d[1] = 0;
|
||||
d->mac.d[2] = 0;
|
||||
d->mac.ucode_cmd = 0;
|
||||
/* use dst index 0 */
|
||||
d->mac.d[1] |= BIT(MAC_CFG_DESC_TX_1_DST_INDEX_EN_POS) |
|
||||
(0 << MAC_CFG_DESC_TX_1_DST_INDEX_POS);
|
||||
/* translation type: 0 - bypass; 1 - 802.3; 2 - native wifi */
|
||||
d->mac.d[2] = BIT(MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_POS) |
|
||||
(1 << MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_POS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct device *dev = wil_to_dev(wil);
|
||||
volatile struct vring_tx_desc *d;
|
||||
u32 swhead = vring->swhead;
|
||||
int avail = wil_vring_avail_tx(vring);
|
||||
int nr_frags = skb_shinfo(skb)->nr_frags;
|
||||
uint f;
|
||||
int vring_index = vring - wil->vring_tx;
|
||||
uint i = swhead;
|
||||
dma_addr_t pa;
|
||||
|
||||
wil_dbg_TXRX(wil, "%s()\n", __func__);
|
||||
|
||||
if (avail < vring->size/8)
|
||||
netif_tx_stop_all_queues(wil_to_ndev(wil));
|
||||
if (avail < 1 + nr_frags) {
|
||||
wil_err(wil, "Tx ring full. No space for %d fragments\n",
|
||||
1 + nr_frags);
|
||||
return -ENOMEM;
|
||||
}
|
||||
d = &(vring->va[i].tx);
|
||||
|
||||
/* FIXME FW can accept only unicast frames for the peer */
|
||||
memcpy(skb->data, wil->dst_addr[vring_index], ETH_ALEN);
|
||||
|
||||
pa = dma_map_single(dev, skb->data,
|
||||
skb_headlen(skb), DMA_TO_DEVICE);
|
||||
|
||||
wil_dbg_TXRX(wil, "Tx skb %d bytes %p -> %#08llx\n", skb_headlen(skb),
|
||||
skb->data, (unsigned long long)pa);
|
||||
wil_hex_dump_TXRX("Tx ", DUMP_PREFIX_OFFSET, 16, 1,
|
||||
skb->data, skb_headlen(skb), false);
|
||||
|
||||
if (unlikely(dma_mapping_error(dev, pa)))
|
||||
return -EINVAL;
|
||||
/* 1-st segment */
|
||||
wil_tx_desc_map(d, pa, skb_headlen(skb));
|
||||
d->mac.d[2] |= ((nr_frags + 1) <<
|
||||
MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS);
|
||||
/* middle segments */
|
||||
for (f = 0; f < nr_frags; f++) {
|
||||
const struct skb_frag_struct *frag =
|
||||
&skb_shinfo(skb)->frags[f];
|
||||
int len = skb_frag_size(frag);
|
||||
i = (swhead + f + 1) % vring->size;
|
||||
d = &(vring->va[i].tx);
|
||||
pa = skb_frag_dma_map(dev, frag, 0, skb_frag_size(frag),
|
||||
DMA_TO_DEVICE);
|
||||
if (unlikely(dma_mapping_error(dev, pa)))
|
||||
goto dma_error;
|
||||
wil_tx_desc_map(d, pa, len);
|
||||
vring->ctx[i] = NULL;
|
||||
}
|
||||
/* for the last seg only */
|
||||
d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_EOP_POS);
|
||||
d->dma.d0 |= BIT(9); /* BUG: undocumented bit */
|
||||
d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS);
|
||||
d->dma.d0 |= (vring_index << DMA_CFG_DESC_TX_0_QID_POS);
|
||||
|
||||
wil_hex_dump_TXRX("Tx ", DUMP_PREFIX_NONE, 32, 4,
|
||||
(const void *)d, sizeof(*d), false);
|
||||
|
||||
/* advance swhead */
|
||||
wil_vring_advance_head(vring, nr_frags + 1);
|
||||
wil_dbg_TXRX(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead);
|
||||
iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail));
|
||||
/* hold reference to skb
|
||||
* to prevent skb release before accounting
|
||||
* in case of immediate "tx done"
|
||||
*/
|
||||
vring->ctx[i] = skb_get(skb);
|
||||
|
||||
return 0;
|
||||
dma_error:
|
||||
/* unmap what we have mapped */
|
||||
/* Note: increment @f to operate with positive index */
|
||||
for (f++; f > 0; f--) {
|
||||
i = (swhead + f) % vring->size;
|
||||
d = &(vring->va[i].tx);
|
||||
d->dma.status = TX_DMA_STATUS_DU;
|
||||
pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32);
|
||||
if (vring->ctx[i])
|
||||
dma_unmap_single(dev, pa, d->dma.length, DMA_TO_DEVICE);
|
||||
else
|
||||
dma_unmap_page(dev, pa, d->dma.length, DMA_TO_DEVICE);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
|
||||
{
|
||||
struct wil6210_priv *wil = ndev_to_wil(ndev);
|
||||
struct vring *vring;
|
||||
int rc;
|
||||
|
||||
wil_dbg_TXRX(wil, "%s()\n", __func__);
|
||||
if (!test_bit(wil_status_fwready, &wil->status)) {
|
||||
wil_err(wil, "FW not ready\n");
|
||||
goto drop;
|
||||
}
|
||||
if (!test_bit(wil_status_fwconnected, &wil->status)) {
|
||||
wil_err(wil, "FW not connected\n");
|
||||
goto drop;
|
||||
}
|
||||
if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) {
|
||||
wil_err(wil, "Xmit in monitor mode not supported\n");
|
||||
goto drop;
|
||||
}
|
||||
if (skb->protocol == cpu_to_be16(ETH_P_PAE)) {
|
||||
rc = wmi_tx_eapol(wil, skb);
|
||||
} else {
|
||||
/* find vring */
|
||||
vring = wil_find_tx_vring(wil, skb);
|
||||
if (!vring) {
|
||||
wil_err(wil, "No Tx VRING available\n");
|
||||
goto drop;
|
||||
}
|
||||
/* set up vring entry */
|
||||
rc = wil_tx_vring(wil, vring, skb);
|
||||
}
|
||||
switch (rc) {
|
||||
case 0:
|
||||
ndev->stats.tx_packets++;
|
||||
ndev->stats.tx_bytes += skb->len;
|
||||
dev_kfree_skb_any(skb);
|
||||
return NETDEV_TX_OK;
|
||||
case -ENOMEM:
|
||||
return NETDEV_TX_BUSY;
|
||||
default:
|
||||
; /* goto drop; */
|
||||
break;
|
||||
}
|
||||
drop:
|
||||
netif_tx_stop_all_queues(ndev);
|
||||
ndev->stats.tx_dropped++;
|
||||
dev_kfree_skb_any(skb);
|
||||
|
||||
return NET_XMIT_DROP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up transmitted skb's from the Tx VRING
|
||||
*
|
||||
* Safe to call from IRQ
|
||||
*/
|
||||
void wil_tx_complete(struct wil6210_priv *wil, int ringid)
|
||||
{
|
||||
struct device *dev = wil_to_dev(wil);
|
||||
struct vring *vring = &wil->vring_tx[ringid];
|
||||
|
||||
if (!vring->va) {
|
||||
wil_err(wil, "Tx irq[%d]: vring not initialized\n", ringid);
|
||||
return;
|
||||
}
|
||||
|
||||
wil_dbg_TXRX(wil, "%s(%d)\n", __func__, ringid);
|
||||
|
||||
while (!wil_vring_is_empty(vring)) {
|
||||
volatile struct vring_tx_desc *d = &vring->va[vring->swtail].tx;
|
||||
dma_addr_t pa;
|
||||
struct sk_buff *skb;
|
||||
if (!(d->dma.status & TX_DMA_STATUS_DU))
|
||||
break;
|
||||
|
||||
wil_dbg_TXRX(wil,
|
||||
"Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n",
|
||||
vring->swtail, d->dma.length, d->dma.status,
|
||||
d->dma.error);
|
||||
wil_hex_dump_TXRX("TxC ", DUMP_PREFIX_NONE, 32, 4,
|
||||
(const void *)d, sizeof(*d), false);
|
||||
|
||||
pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32);
|
||||
skb = vring->ctx[vring->swtail];
|
||||
if (skb) {
|
||||
dma_unmap_single(dev, pa, d->dma.length, DMA_TO_DEVICE);
|
||||
dev_kfree_skb_any(skb);
|
||||
vring->ctx[vring->swtail] = NULL;
|
||||
} else {
|
||||
dma_unmap_page(dev, pa, d->dma.length, DMA_TO_DEVICE);
|
||||
}
|
||||
d->dma.addr_low = 0;
|
||||
d->dma.addr_high = 0;
|
||||
d->dma.length = 0;
|
||||
d->dma.status = TX_DMA_STATUS_DU;
|
||||
vring->swtail = wil_vring_next_tail(vring);
|
||||
}
|
||||
if (wil_vring_avail_tx(vring) > vring->size/4)
|
||||
netif_tx_wake_all_queues(wil_to_ndev(wil));
|
||||
}
|
362
drivers/net/wireless/ath/wil6210/txrx.h
Normal file
362
drivers/net/wireless/ath/wil6210/txrx.h
Normal file
|
@ -0,0 +1,362 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Qualcomm Atheros, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef WIL6210_TXRX_H
|
||||
#define WIL6210_TXRX_H
|
||||
|
||||
#define BUF_SW_OWNED (1)
|
||||
#define BUF_HW_OWNED (0)
|
||||
|
||||
/* size of max. Rx packet */
|
||||
#define RX_BUF_LEN (2048)
|
||||
#define TX_BUF_LEN (2048)
|
||||
/* how many bytes to reserve for rtap header? */
|
||||
#define WIL6210_RTAP_SIZE (128)
|
||||
|
||||
/* Tx/Rx path */
|
||||
/*
|
||||
* Tx descriptor - MAC part
|
||||
* [dword 0]
|
||||
* bit 0.. 9 : lifetime_expiry_value:10
|
||||
* bit 10 : interrup_en:1
|
||||
* bit 11 : status_en:1
|
||||
* bit 12..13 : txss_override:2
|
||||
* bit 14 : timestamp_insertion:1
|
||||
* bit 15 : duration_preserve:1
|
||||
* bit 16..21 : reserved0:6
|
||||
* bit 22..26 : mcs_index:5
|
||||
* bit 27 : mcs_en:1
|
||||
* bit 28..29 : reserved1:2
|
||||
* bit 30 : reserved2:1
|
||||
* bit 31 : sn_preserved:1
|
||||
* [dword 1]
|
||||
* bit 0.. 3 : pkt_mode:4
|
||||
* bit 4 : pkt_mode_en:1
|
||||
* bit 5.. 7 : reserved0:3
|
||||
* bit 8..13 : reserved1:6
|
||||
* bit 14 : reserved2:1
|
||||
* bit 15 : ack_policy_en:1
|
||||
* bit 16..19 : dst_index:4
|
||||
* bit 20 : dst_index_en:1
|
||||
* bit 21..22 : ack_policy:2
|
||||
* bit 23 : lifetime_en:1
|
||||
* bit 24..30 : max_retry:7
|
||||
* bit 31 : max_retry_en:1
|
||||
* [dword 2]
|
||||
* bit 0.. 7 : num_of_descriptors:8
|
||||
* bit 8..17 : reserved:10
|
||||
* bit 18..19 : l2_translation_type:2
|
||||
* bit 20 : snap_hdr_insertion_en:1
|
||||
* bit 21 : vlan_removal_en:1
|
||||
* bit 22..31 : reserved0:10
|
||||
* [dword 3]
|
||||
* bit 0.. 31: ucode_cmd:32
|
||||
*/
|
||||
struct vring_tx_mac {
|
||||
u32 d[3];
|
||||
u32 ucode_cmd;
|
||||
} __packed;
|
||||
|
||||
/* TX MAC Dword 0 */
|
||||
#define MAC_CFG_DESC_TX_0_LIFETIME_EXPIRY_VALUE_POS 0
|
||||
#define MAC_CFG_DESC_TX_0_LIFETIME_EXPIRY_VALUE_LEN 10
|
||||
#define MAC_CFG_DESC_TX_0_LIFETIME_EXPIRY_VALUE_MSK 0x3FF
|
||||
|
||||
#define MAC_CFG_DESC_TX_0_INTERRUP_EN_POS 10
|
||||
#define MAC_CFG_DESC_TX_0_INTERRUP_EN_LEN 1
|
||||
#define MAC_CFG_DESC_TX_0_INTERRUP_EN_MSK 0x400
|
||||
|
||||
#define MAC_CFG_DESC_TX_0_STATUS_EN_POS 11
|
||||
#define MAC_CFG_DESC_TX_0_STATUS_EN_LEN 1
|
||||
#define MAC_CFG_DESC_TX_0_STATUS_EN_MSK 0x800
|
||||
|
||||
#define MAC_CFG_DESC_TX_0_TXSS_OVERRIDE_POS 12
|
||||
#define MAC_CFG_DESC_TX_0_TXSS_OVERRIDE_LEN 2
|
||||
#define MAC_CFG_DESC_TX_0_TXSS_OVERRIDE_MSK 0x3000
|
||||
|
||||
#define MAC_CFG_DESC_TX_0_TIMESTAMP_INSERTION_POS 14
|
||||
#define MAC_CFG_DESC_TX_0_TIMESTAMP_INSERTION_LEN 1
|
||||
#define MAC_CFG_DESC_TX_0_TIMESTAMP_INSERTION_MSK 0x4000
|
||||
|
||||
#define MAC_CFG_DESC_TX_0_DURATION_PRESERVE_POS 15
|
||||
#define MAC_CFG_DESC_TX_0_DURATION_PRESERVE_LEN 1
|
||||
#define MAC_CFG_DESC_TX_0_DURATION_PRESERVE_MSK 0x8000
|
||||
|
||||
#define MAC_CFG_DESC_TX_0_MCS_INDEX_POS 22
|
||||
#define MAC_CFG_DESC_TX_0_MCS_INDEX_LEN 5
|
||||
#define MAC_CFG_DESC_TX_0_MCS_INDEX_MSK 0x7C00000
|
||||
|
||||
#define MAC_CFG_DESC_TX_0_MCS_EN_POS 27
|
||||
#define MAC_CFG_DESC_TX_0_MCS_EN_LEN 1
|
||||
#define MAC_CFG_DESC_TX_0_MCS_EN_MSK 0x8000000
|
||||
|
||||
#define MAC_CFG_DESC_TX_0_SN_PRESERVED_POS 31
|
||||
#define MAC_CFG_DESC_TX_0_SN_PRESERVED_LEN 1
|
||||
#define MAC_CFG_DESC_TX_0_SN_PRESERVED_MSK 0x80000000
|
||||
|
||||
/* TX MAC Dword 1 */
|
||||
#define MAC_CFG_DESC_TX_1_PKT_MODE_POS 0
|
||||
#define MAC_CFG_DESC_TX_1_PKT_MODE_LEN 4
|
||||
#define MAC_CFG_DESC_TX_1_PKT_MODE_MSK 0xF
|
||||
|
||||
#define MAC_CFG_DESC_TX_1_PKT_MODE_EN_POS 4
|
||||
#define MAC_CFG_DESC_TX_1_PKT_MODE_EN_LEN 1
|
||||
#define MAC_CFG_DESC_TX_1_PKT_MODE_EN_MSK 0x10
|
||||
|
||||
#define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_POS 15
|
||||
#define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_LEN 1
|
||||
#define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_MSK 0x8000
|
||||
|
||||
#define MAC_CFG_DESC_TX_1_DST_INDEX_POS 16
|
||||
#define MAC_CFG_DESC_TX_1_DST_INDEX_LEN 4
|
||||
#define MAC_CFG_DESC_TX_1_DST_INDEX_MSK 0xF0000
|
||||
|
||||
#define MAC_CFG_DESC_TX_1_DST_INDEX_EN_POS 20
|
||||
#define MAC_CFG_DESC_TX_1_DST_INDEX_EN_LEN 1
|
||||
#define MAC_CFG_DESC_TX_1_DST_INDEX_EN_MSK 0x100000
|
||||
|
||||
#define MAC_CFG_DESC_TX_1_ACK_POLICY_POS 21
|
||||
#define MAC_CFG_DESC_TX_1_ACK_POLICY_LEN 2
|
||||
#define MAC_CFG_DESC_TX_1_ACK_POLICY_MSK 0x600000
|
||||
|
||||
#define MAC_CFG_DESC_TX_1_LIFETIME_EN_POS 23
|
||||
#define MAC_CFG_DESC_TX_1_LIFETIME_EN_LEN 1
|
||||
#define MAC_CFG_DESC_TX_1_LIFETIME_EN_MSK 0x800000
|
||||
|
||||
#define MAC_CFG_DESC_TX_1_MAX_RETRY_POS 24
|
||||
#define MAC_CFG_DESC_TX_1_MAX_RETRY_LEN 7
|
||||
#define MAC_CFG_DESC_TX_1_MAX_RETRY_MSK 0x7F000000
|
||||
|
||||
#define MAC_CFG_DESC_TX_1_MAX_RETRY_EN_POS 31
|
||||
#define MAC_CFG_DESC_TX_1_MAX_RETRY_EN_LEN 1
|
||||
#define MAC_CFG_DESC_TX_1_MAX_RETRY_EN_MSK 0x80000000
|
||||
|
||||
/* TX MAC Dword 2 */
|
||||
#define MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS 0
|
||||
#define MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_LEN 8
|
||||
#define MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_MSK 0xFF
|
||||
|
||||
#define MAC_CFG_DESC_TX_2_RESERVED_POS 8
|
||||
#define MAC_CFG_DESC_TX_2_RESERVED_LEN 10
|
||||
#define MAC_CFG_DESC_TX_2_RESERVED_MSK 0x3FF00
|
||||
|
||||
#define MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_POS 18
|
||||
#define MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_LEN 2
|
||||
#define MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_MSK 0xC0000
|
||||
|
||||
#define MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_POS 20
|
||||
#define MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_LEN 1
|
||||
#define MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_MSK 0x100000
|
||||
|
||||
#define MAC_CFG_DESC_TX_2_VLAN_REMOVAL_EN_POS 21
|
||||
#define MAC_CFG_DESC_TX_2_VLAN_REMOVAL_EN_LEN 1
|
||||
#define MAC_CFG_DESC_TX_2_VLAN_REMOVAL_EN_MSK 0x200000
|
||||
|
||||
/* TX MAC Dword 3 */
|
||||
#define MAC_CFG_DESC_TX_3_UCODE_CMD_POS 0
|
||||
#define MAC_CFG_DESC_TX_3_UCODE_CMD_LEN 32
|
||||
#define MAC_CFG_DESC_TX_3_UCODE_CMD_MSK 0xFFFFFFFF
|
||||
|
||||
/* TX DMA Dword 0 */
|
||||
#define DMA_CFG_DESC_TX_0_L4_LENGTH_POS 0
|
||||
#define DMA_CFG_DESC_TX_0_L4_LENGTH_LEN 8
|
||||
#define DMA_CFG_DESC_TX_0_L4_LENGTH_MSK 0xFF
|
||||
|
||||
#define DMA_CFG_DESC_TX_0_CMD_EOP_POS 8
|
||||
#define DMA_CFG_DESC_TX_0_CMD_EOP_LEN 1
|
||||
#define DMA_CFG_DESC_TX_0_CMD_EOP_MSK 0x100
|
||||
|
||||
#define DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS 10
|
||||
#define DMA_CFG_DESC_TX_0_CMD_DMA_IT_LEN 1
|
||||
#define DMA_CFG_DESC_TX_0_CMD_DMA_IT_MSK 0x400
|
||||
|
||||
#define DMA_CFG_DESC_TX_0_SEGMENT_BUF_DETAILS_POS 11
|
||||
#define DMA_CFG_DESC_TX_0_SEGMENT_BUF_DETAILS_LEN 2
|
||||
#define DMA_CFG_DESC_TX_0_SEGMENT_BUF_DETAILS_MSK 0x1800
|
||||
|
||||
#define DMA_CFG_DESC_TX_0_TCP_SEG_EN_POS 13
|
||||
#define DMA_CFG_DESC_TX_0_TCP_SEG_EN_LEN 1
|
||||
#define DMA_CFG_DESC_TX_0_TCP_SEG_EN_MSK 0x2000
|
||||
|
||||
#define DMA_CFG_DESC_TX_0_IPV4_CHECKSUM_EN_POS 14
|
||||
#define DMA_CFG_DESC_TX_0_IPV4_CHECKSUM_EN_LEN 1
|
||||
#define DMA_CFG_DESC_TX_0_IPV4_CHECKSUM_EN_MSK 0x4000
|
||||
|
||||
#define DMA_CFG_DESC_TX_0_TCP_UDP_CHECKSUM_EN_POS 15
|
||||
#define DMA_CFG_DESC_TX_0_TCP_UDP_CHECKSUM_EN_LEN 1
|
||||
#define DMA_CFG_DESC_TX_0_TCP_UDP_CHECKSUM_EN_MSK 0x8000
|
||||
|
||||
#define DMA_CFG_DESC_TX_0_QID_POS 16
|
||||
#define DMA_CFG_DESC_TX_0_QID_LEN 5
|
||||
#define DMA_CFG_DESC_TX_0_QID_MSK 0x1F0000
|
||||
|
||||
#define DMA_CFG_DESC_TX_0_PSEUDO_HEADER_CALC_EN_POS 21
|
||||
#define DMA_CFG_DESC_TX_0_PSEUDO_HEADER_CALC_EN_LEN 1
|
||||
#define DMA_CFG_DESC_TX_0_PSEUDO_HEADER_CALC_EN_MSK 0x200000
|
||||
|
||||
#define DMA_CFG_DESC_TX_0_L4_TYPE_POS 30
|
||||
#define DMA_CFG_DESC_TX_0_L4_TYPE_LEN 2
|
||||
#define DMA_CFG_DESC_TX_0_L4_TYPE_MSK 0xC0000000
|
||||
|
||||
|
||||
#define TX_DMA_STATUS_DU BIT(0)
|
||||
|
||||
struct vring_tx_dma {
|
||||
u32 d0;
|
||||
u32 addr_low;
|
||||
u16 addr_high;
|
||||
u8 ip_length;
|
||||
u8 b11; /* 0..6: mac_length; 7:ip_version */
|
||||
u8 error; /* 0..2: err; 3..7: reserved; */
|
||||
u8 status; /* 0: used; 1..7; reserved */
|
||||
u16 length;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Rx descriptor - MAC part
|
||||
* [dword 0]
|
||||
* bit 0.. 3 : tid:4 The QoS (b3-0) TID Field
|
||||
* bit 4.. 6 : connection_id:3 :The Source index that was found during
|
||||
* Parsing the TA. This field is used to define the source of the packet
|
||||
* bit 7 : reserved:1
|
||||
* bit 8.. 9 : mac_id:2 : The MAC virtual Ring number (always zero)
|
||||
* bit 10..11 : frame_type:2 : The FC Control (b3-2) - MPDU Type
|
||||
* (management, data, control and extension)
|
||||
* bit 12..15 : frame_subtype:4 : The FC Control (b7-4) - Frame Subtype
|
||||
* bit 16..27 : seq_number:12 The received Sequence number field
|
||||
* bit 28..31 : extended:4 extended subtype
|
||||
* [dword 1]
|
||||
* bit 0.. 3 : reserved
|
||||
* bit 4.. 5 : key_id:2
|
||||
* bit 6 : decrypt_bypass:1
|
||||
* bit 7 : security:1
|
||||
* bit 8.. 9 : ds_bits:2
|
||||
* bit 10 : a_msdu_present:1 from qos header
|
||||
* bit 11 : a_msdu_type:1 from qos header
|
||||
* bit 12 : a_mpdu:1 part of AMPDU aggregation
|
||||
* bit 13 : broadcast:1
|
||||
* bit 14 : mutlicast:1
|
||||
* bit 15 : reserved:1
|
||||
* bit 16..20 : rx_mac_qid:5 The Queue Identifier that the packet
|
||||
* is received from
|
||||
* bit 21..24 : mcs:4
|
||||
* bit 25..28 : mic_icr:4
|
||||
* bit 29..31 : reserved:3
|
||||
* [dword 2]
|
||||
* bit 0.. 2 : time_slot:3 The timeslot that the MPDU is received
|
||||
* bit 3 : fc_protocol_ver:1 The FC Control (b0) - Protocol Version
|
||||
* bit 4 : fc_order:1 The FC Control (b15) -Order
|
||||
* bit 5.. 7 : qos_ack_policy:3 The QoS (b6-5) ack policy Field
|
||||
* bit 8 : esop:1 The QoS (b4) ESOP field
|
||||
* bit 9 : qos_rdg_more_ppdu:1 The QoS (b9) RDG field
|
||||
* bit 10..14 : qos_reserved:5 The QoS (b14-10) Reserved field
|
||||
* bit 15 : qos_ac_constraint:1
|
||||
* bit 16..31 : pn_15_0:16 low 2 bytes of PN
|
||||
* [dword 3]
|
||||
* bit 0..31 : pn_47_16:32 high 4 bytes of PN
|
||||
*/
|
||||
struct vring_rx_mac {
|
||||
u32 d0;
|
||||
u32 d1;
|
||||
u16 w4;
|
||||
u16 pn_15_0;
|
||||
u32 pn_47_16;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Rx descriptor - DMA part
|
||||
* [dword 0]
|
||||
* bit 0.. 7 : l4_length:8 layer 4 length
|
||||
* bit 8.. 9 : reserved:2
|
||||
* bit 10 : cmd_dma_it:1
|
||||
* bit 11..15 : reserved:5
|
||||
* bit 16..29 : phy_info_length:14
|
||||
* bit 30..31 : l4_type:2 valid if the L4I bit is set in the status field
|
||||
* [dword 1]
|
||||
* bit 0..31 : addr_low:32 The payload buffer low address
|
||||
* [dword 2]
|
||||
* bit 0..15 : addr_high:16 The payload buffer high address
|
||||
* bit 16..23 : ip_length:8
|
||||
* bit 24..30 : mac_length:7
|
||||
* bit 31 : ip_version:1
|
||||
* [dword 3]
|
||||
* [byte 12] error
|
||||
* [byte 13] status
|
||||
* bit 0 : du:1
|
||||
* bit 1 : eop:1
|
||||
* bit 2 : error:1
|
||||
* bit 3 : mi:1
|
||||
* bit 4 : l3_identified:1
|
||||
* bit 5 : l4_identified:1
|
||||
* bit 6 : phy_info_included:1
|
||||
* bit 7 : reserved:1
|
||||
* [word 7] length
|
||||
*
|
||||
*/
|
||||
|
||||
#define RX_DMA_D0_CMD_DMA_IT BIT(10)
|
||||
|
||||
#define RX_DMA_STATUS_DU BIT(0)
|
||||
#define RX_DMA_STATUS_ERROR BIT(2)
|
||||
#define RX_DMA_STATUS_PHY_INFO BIT(6)
|
||||
|
||||
struct vring_rx_dma {
|
||||
u32 d0;
|
||||
u32 addr_low;
|
||||
u16 addr_high;
|
||||
u8 ip_length;
|
||||
u8 b11;
|
||||
u8 error;
|
||||
u8 status;
|
||||
u16 length;
|
||||
} __packed;
|
||||
|
||||
struct vring_tx_desc {
|
||||
struct vring_tx_mac mac;
|
||||
struct vring_tx_dma dma;
|
||||
} __packed;
|
||||
|
||||
struct vring_rx_desc {
|
||||
struct vring_rx_mac mac;
|
||||
struct vring_rx_dma dma;
|
||||
} __packed;
|
||||
|
||||
union vring_desc {
|
||||
struct vring_tx_desc tx;
|
||||
struct vring_rx_desc rx;
|
||||
} __packed;
|
||||
|
||||
static inline int wil_rxdesc_phy_length(volatile struct vring_rx_desc *d)
|
||||
{
|
||||
return WIL_GET_BITS(d->dma.d0, 16, 29);
|
||||
}
|
||||
|
||||
static inline int wil_rxdesc_mcs(volatile struct vring_rx_desc *d)
|
||||
{
|
||||
return WIL_GET_BITS(d->mac.d1, 21, 24);
|
||||
}
|
||||
|
||||
static inline int wil_rxdesc_ds_bits(volatile struct vring_rx_desc *d)
|
||||
{
|
||||
return WIL_GET_BITS(d->mac.d1, 8, 9);
|
||||
}
|
||||
|
||||
static inline int wil_rxdesc_ftype(volatile struct vring_rx_desc *d)
|
||||
{
|
||||
return WIL_GET_BITS(d->mac.d0, 10, 11);
|
||||
}
|
||||
|
||||
#endif /* WIL6210_TXRX_H */
|
363
drivers/net/wireless/ath/wil6210/wil6210.h
Normal file
363
drivers/net/wireless/ath/wil6210/wil6210.h
Normal file
|
@ -0,0 +1,363 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Qualcomm Atheros, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __WIL6210_H__
|
||||
#define __WIL6210_H__
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <net/cfg80211.h>
|
||||
|
||||
#include "dbg_hexdump.h"
|
||||
|
||||
#define WIL_NAME "wil6210"
|
||||
|
||||
/**
|
||||
* extract bits [@b0:@b1] (inclusive) from the value @x
|
||||
* it should be @b0 <= @b1, or result is incorrect
|
||||
*/
|
||||
static inline u32 WIL_GET_BITS(u32 x, int b0, int b1)
|
||||
{
|
||||
return (x >> b0) & ((1 << (b1 - b0 + 1)) - 1);
|
||||
}
|
||||
|
||||
#define WIL6210_MEM_SIZE (2*1024*1024UL)
|
||||
|
||||
#define WIL6210_TX_QUEUES (4)
|
||||
|
||||
#define WIL6210_RX_RING_SIZE (128)
|
||||
#define WIL6210_TX_RING_SIZE (128)
|
||||
#define WIL6210_MAX_TX_RINGS (24)
|
||||
|
||||
/* Hardware definitions begin */
|
||||
|
||||
/*
|
||||
* Mapping
|
||||
* RGF File | Host addr | FW addr
|
||||
* | |
|
||||
* user_rgf | 0x000000 | 0x880000
|
||||
* dma_rgf | 0x001000 | 0x881000
|
||||
* pcie_rgf | 0x002000 | 0x882000
|
||||
* | |
|
||||
*/
|
||||
|
||||
/* Where various structures placed in host address space */
|
||||
#define WIL6210_FW_HOST_OFF (0x880000UL)
|
||||
|
||||
#define HOSTADDR(fwaddr) (fwaddr - WIL6210_FW_HOST_OFF)
|
||||
|
||||
/*
|
||||
* Interrupt control registers block
|
||||
*
|
||||
* each interrupt controlled by the same bit in all registers
|
||||
*/
|
||||
struct RGF_ICR {
|
||||
u32 ICC; /* Cause Control, RW: 0 - W1C, 1 - COR */
|
||||
u32 ICR; /* Cause, W1C/COR depending on ICC */
|
||||
u32 ICM; /* Cause masked (ICR & ~IMV), W1C/COR depending on ICC */
|
||||
u32 ICS; /* Cause Set, WO */
|
||||
u32 IMV; /* Mask, RW+S/C */
|
||||
u32 IMS; /* Mask Set, write 1 to set */
|
||||
u32 IMC; /* Mask Clear, write 1 to clear */
|
||||
} __packed;
|
||||
|
||||
/* registers - FW addresses */
|
||||
#define RGF_USER_USER_SCRATCH_PAD (0x8802bc)
|
||||
#define RGF_USER_USER_ICR (0x880b4c) /* struct RGF_ICR */
|
||||
#define BIT_USER_USER_ICR_SW_INT_2 BIT(18)
|
||||
#define RGF_USER_CLKS_CTL_SW_RST_MASK_0 (0x880b14)
|
||||
#define RGF_USER_MAC_CPU_0 (0x8801fc)
|
||||
#define RGF_USER_USER_CPU_0 (0x8801e0)
|
||||
#define RGF_USER_CLKS_CTL_SW_RST_VEC_0 (0x880b04)
|
||||
#define RGF_USER_CLKS_CTL_SW_RST_VEC_1 (0x880b08)
|
||||
#define RGF_USER_CLKS_CTL_SW_RST_VEC_2 (0x880b0c)
|
||||
#define RGF_USER_CLKS_CTL_SW_RST_VEC_3 (0x880b10)
|
||||
|
||||
#define RGF_DMA_PSEUDO_CAUSE (0x881c68)
|
||||
#define RGF_DMA_PSEUDO_CAUSE_MASK_SW (0x881c6c)
|
||||
#define RGF_DMA_PSEUDO_CAUSE_MASK_FW (0x881c70)
|
||||
#define BIT_DMA_PSEUDO_CAUSE_RX BIT(0)
|
||||
#define BIT_DMA_PSEUDO_CAUSE_TX BIT(1)
|
||||
#define BIT_DMA_PSEUDO_CAUSE_MISC BIT(2)
|
||||
|
||||
#define RGF_DMA_EP_TX_ICR (0x881bb4) /* struct RGF_ICR */
|
||||
#define BIT_DMA_EP_TX_ICR_TX_DONE BIT(0)
|
||||
#define BIT_DMA_EP_TX_ICR_TX_DONE_N(n) BIT(n+1) /* n = [0..23] */
|
||||
#define RGF_DMA_EP_RX_ICR (0x881bd0) /* struct RGF_ICR */
|
||||
#define BIT_DMA_EP_RX_ICR_RX_DONE BIT(0)
|
||||
#define RGF_DMA_EP_MISC_ICR (0x881bec) /* struct RGF_ICR */
|
||||
#define BIT_DMA_EP_MISC_ICR_RX_HTRSH BIT(0)
|
||||
#define BIT_DMA_EP_MISC_ICR_TX_NO_ACT BIT(1)
|
||||
#define BIT_DMA_EP_MISC_ICR_FW_INT0 BIT(28)
|
||||
#define BIT_DMA_EP_MISC_ICR_FW_INT1 BIT(29)
|
||||
|
||||
/* Interrupt moderation control */
|
||||
#define RGF_DMA_ITR_CNT_TRSH (0x881c5c)
|
||||
#define RGF_DMA_ITR_CNT_DATA (0x881c60)
|
||||
#define RGF_DMA_ITR_CNT_CRL (0x881C64)
|
||||
#define BIT_DMA_ITR_CNT_CRL_EN BIT(0)
|
||||
#define BIT_DMA_ITR_CNT_CRL_EXT_TICK BIT(1)
|
||||
#define BIT_DMA_ITR_CNT_CRL_FOREVER BIT(2)
|
||||
#define BIT_DMA_ITR_CNT_CRL_CLR BIT(3)
|
||||
#define BIT_DMA_ITR_CNT_CRL_REACH_TRSH BIT(4)
|
||||
|
||||
/* popular locations */
|
||||
#define HOST_MBOX HOSTADDR(RGF_USER_USER_SCRATCH_PAD)
|
||||
#define HOST_SW_INT (HOSTADDR(RGF_USER_USER_ICR) + \
|
||||
offsetof(struct RGF_ICR, ICS))
|
||||
#define SW_INT_MBOX BIT_USER_USER_ICR_SW_INT_2
|
||||
|
||||
/* ISR register bits */
|
||||
#define ISR_MISC_FW_READY BIT_DMA_EP_MISC_ICR_FW_INT0
|
||||
#define ISR_MISC_MBOX_EVT BIT_DMA_EP_MISC_ICR_FW_INT1
|
||||
|
||||
/* Hardware definitions end */
|
||||
|
||||
struct wil6210_mbox_ring {
|
||||
u32 base;
|
||||
u16 entry_size; /* max. size of mbox entry, incl. all headers */
|
||||
u16 size;
|
||||
u32 tail;
|
||||
u32 head;
|
||||
} __packed;
|
||||
|
||||
struct wil6210_mbox_ring_desc {
|
||||
__le32 sync;
|
||||
__le32 addr;
|
||||
} __packed;
|
||||
|
||||
/* at HOST_OFF_WIL6210_MBOX_CTL */
|
||||
struct wil6210_mbox_ctl {
|
||||
struct wil6210_mbox_ring tx;
|
||||
struct wil6210_mbox_ring rx;
|
||||
} __packed;
|
||||
|
||||
struct wil6210_mbox_hdr {
|
||||
__le16 seq;
|
||||
__le16 len; /* payload, bytes after this header */
|
||||
__le16 type;
|
||||
u8 flags;
|
||||
u8 reserved;
|
||||
} __packed;
|
||||
|
||||
#define WIL_MBOX_HDR_TYPE_WMI (0)
|
||||
|
||||
/* max. value for wil6210_mbox_hdr.len */
|
||||
#define MAX_MBOXITEM_SIZE (240)
|
||||
|
||||
struct wil6210_mbox_hdr_wmi {
|
||||
u8 reserved0[2];
|
||||
__le16 id;
|
||||
__le16 info1; /* bits [0..3] - device_id, rest - unused */
|
||||
u8 reserved1[2];
|
||||
} __packed;
|
||||
|
||||
struct pending_wmi_event {
|
||||
struct list_head list;
|
||||
struct {
|
||||
struct wil6210_mbox_hdr hdr;
|
||||
struct wil6210_mbox_hdr_wmi wmi;
|
||||
u8 data[0];
|
||||
} __packed event;
|
||||
};
|
||||
|
||||
union vring_desc;
|
||||
|
||||
struct vring {
|
||||
dma_addr_t pa;
|
||||
volatile union vring_desc *va; /* vring_desc[size], WriteBack by DMA */
|
||||
u16 size; /* number of vring_desc elements */
|
||||
u32 swtail;
|
||||
u32 swhead;
|
||||
u32 hwtail; /* write here to inform hw */
|
||||
void **ctx; /* void *ctx[size] - software context */
|
||||
};
|
||||
|
||||
enum { /* for wil6210_priv.status */
|
||||
wil_status_fwready = 0,
|
||||
wil_status_fwconnected,
|
||||
wil_status_dontscan,
|
||||
wil_status_irqen, /* FIXME: interrupts enabled - for debug */
|
||||
};
|
||||
|
||||
struct pci_dev;
|
||||
|
||||
struct wil6210_stats {
|
||||
u64 tsf;
|
||||
u32 snr;
|
||||
u16 last_mcs_rx;
|
||||
u16 bf_mcs; /* last BF, used for Tx */
|
||||
u16 my_rx_sector;
|
||||
u16 my_tx_sector;
|
||||
u16 peer_rx_sector;
|
||||
u16 peer_tx_sector;
|
||||
};
|
||||
|
||||
struct wil6210_priv {
|
||||
struct pci_dev *pdev;
|
||||
int n_msi;
|
||||
struct wireless_dev *wdev;
|
||||
void __iomem *csr;
|
||||
ulong status;
|
||||
/* profile */
|
||||
u32 monitor_flags;
|
||||
u32 secure_pcp; /* create secure PCP? */
|
||||
int sinfo_gen;
|
||||
/* cached ISR registers */
|
||||
u32 isr_misc;
|
||||
/* mailbox related */
|
||||
struct mutex wmi_mutex;
|
||||
struct wil6210_mbox_ctl mbox_ctl;
|
||||
struct completion wmi_ready;
|
||||
u16 wmi_seq;
|
||||
u16 reply_id; /**< wait for this WMI event */
|
||||
void *reply_buf;
|
||||
u16 reply_size;
|
||||
struct workqueue_struct *wmi_wq; /* for deferred calls */
|
||||
struct work_struct wmi_event_worker;
|
||||
struct workqueue_struct *wmi_wq_conn; /* for connect worker */
|
||||
struct work_struct wmi_connect_worker;
|
||||
struct work_struct disconnect_worker;
|
||||
struct timer_list connect_timer;
|
||||
int pending_connect_cid;
|
||||
struct list_head pending_wmi_ev;
|
||||
/*
|
||||
* protect pending_wmi_ev
|
||||
* - fill in IRQ from wil6210_irq_misc,
|
||||
* - consumed in thread by wmi_event_worker
|
||||
*/
|
||||
spinlock_t wmi_ev_lock;
|
||||
/* DMA related */
|
||||
struct vring vring_rx;
|
||||
struct vring vring_tx[WIL6210_MAX_TX_RINGS];
|
||||
u8 dst_addr[WIL6210_MAX_TX_RINGS][ETH_ALEN];
|
||||
/* scan */
|
||||
struct cfg80211_scan_request *scan_request;
|
||||
|
||||
struct mutex mutex; /* for wil6210_priv access in wil_{up|down} */
|
||||
/* statistics */
|
||||
struct wil6210_stats stats;
|
||||
/* debugfs */
|
||||
struct dentry *debug;
|
||||
struct debugfs_blob_wrapper fw_code_blob;
|
||||
struct debugfs_blob_wrapper fw_data_blob;
|
||||
struct debugfs_blob_wrapper fw_peri_blob;
|
||||
struct debugfs_blob_wrapper uc_code_blob;
|
||||
struct debugfs_blob_wrapper uc_data_blob;
|
||||
struct debugfs_blob_wrapper rgf_blob;
|
||||
};
|
||||
|
||||
#define wil_to_wiphy(i) (i->wdev->wiphy)
|
||||
#define wil_to_dev(i) (wiphy_dev(wil_to_wiphy(i)))
|
||||
#define wiphy_to_wil(w) (struct wil6210_priv *)(wiphy_priv(w))
|
||||
#define wil_to_wdev(i) (i->wdev)
|
||||
#define wdev_to_wil(w) (struct wil6210_priv *)(wdev_priv(w))
|
||||
#define wil_to_ndev(i) (wil_to_wdev(i)->netdev)
|
||||
#define ndev_to_wil(n) (wdev_to_wil(n->ieee80211_ptr))
|
||||
|
||||
#define wil_dbg(wil, fmt, arg...) netdev_dbg(wil_to_ndev(wil), fmt, ##arg)
|
||||
#define wil_info(wil, fmt, arg...) netdev_info(wil_to_ndev(wil), fmt, ##arg)
|
||||
#define wil_err(wil, fmt, arg...) netdev_err(wil_to_ndev(wil), fmt, ##arg)
|
||||
|
||||
#define wil_dbg_IRQ(wil, fmt, arg...) wil_dbg(wil, "DBG[ IRQ]" fmt, ##arg)
|
||||
#define wil_dbg_TXRX(wil, fmt, arg...) wil_dbg(wil, "DBG[TXRX]" fmt, ##arg)
|
||||
#define wil_dbg_WMI(wil, fmt, arg...) wil_dbg(wil, "DBG[ WMI]" fmt, ##arg)
|
||||
|
||||
#define wil_hex_dump_TXRX(prefix_str, prefix_type, rowsize, \
|
||||
groupsize, buf, len, ascii) \
|
||||
wil_print_hex_dump_debug("DBG[TXRX]" prefix_str,\
|
||||
prefix_type, rowsize, \
|
||||
groupsize, buf, len, ascii)
|
||||
|
||||
#define wil_hex_dump_WMI(prefix_str, prefix_type, rowsize, \
|
||||
groupsize, buf, len, ascii) \
|
||||
wil_print_hex_dump_debug("DBG[ WMI]" prefix_str,\
|
||||
prefix_type, rowsize, \
|
||||
groupsize, buf, len, ascii)
|
||||
|
||||
void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src,
|
||||
size_t count);
|
||||
void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
|
||||
size_t count);
|
||||
|
||||
void *wil_if_alloc(struct device *dev, void __iomem *csr);
|
||||
void wil_if_free(struct wil6210_priv *wil);
|
||||
int wil_if_add(struct wil6210_priv *wil);
|
||||
void wil_if_remove(struct wil6210_priv *wil);
|
||||
int wil_priv_init(struct wil6210_priv *wil);
|
||||
void wil_priv_deinit(struct wil6210_priv *wil);
|
||||
int wil_reset(struct wil6210_priv *wil);
|
||||
void wil_link_on(struct wil6210_priv *wil);
|
||||
void wil_link_off(struct wil6210_priv *wil);
|
||||
int wil_up(struct wil6210_priv *wil);
|
||||
int wil_down(struct wil6210_priv *wil);
|
||||
void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r);
|
||||
|
||||
void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr);
|
||||
void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr);
|
||||
int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr,
|
||||
struct wil6210_mbox_hdr *hdr);
|
||||
int wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len);
|
||||
void wmi_recv_cmd(struct wil6210_priv *wil);
|
||||
int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
|
||||
u16 reply_id, void *reply, u8 reply_size, int to_msec);
|
||||
void wmi_connect_worker(struct work_struct *work);
|
||||
void wmi_event_worker(struct work_struct *work);
|
||||
void wmi_event_flush(struct wil6210_priv *wil);
|
||||
int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid);
|
||||
int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid);
|
||||
int wmi_set_channel(struct wil6210_priv *wil, int channel);
|
||||
int wmi_get_channel(struct wil6210_priv *wil, int *channel);
|
||||
int wmi_tx_eapol(struct wil6210_priv *wil, struct sk_buff *skb);
|
||||
int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index,
|
||||
const void *mac_addr);
|
||||
int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index,
|
||||
const void *mac_addr, int key_len, const void *key);
|
||||
int wmi_echo(struct wil6210_priv *wil);
|
||||
int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie);
|
||||
|
||||
int wil6210_init_irq(struct wil6210_priv *wil, int irq);
|
||||
void wil6210_fini_irq(struct wil6210_priv *wil, int irq);
|
||||
void wil6210_disable_irq(struct wil6210_priv *wil);
|
||||
void wil6210_enable_irq(struct wil6210_priv *wil);
|
||||
|
||||
int wil6210_debugfs_init(struct wil6210_priv *wil);
|
||||
void wil6210_debugfs_remove(struct wil6210_priv *wil);
|
||||
|
||||
struct wireless_dev *wil_cfg80211_init(struct device *dev);
|
||||
void wil_wdev_free(struct wil6210_priv *wil);
|
||||
|
||||
int wmi_set_mac_address(struct wil6210_priv *wil, void *addr);
|
||||
int wmi_set_bcon(struct wil6210_priv *wil, int bi, u8 wmi_nettype);
|
||||
void wil6210_disconnect(struct wil6210_priv *wil, void *bssid);
|
||||
|
||||
int wil_rx_init(struct wil6210_priv *wil);
|
||||
void wil_rx_fini(struct wil6210_priv *wil);
|
||||
|
||||
/* TX API */
|
||||
int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
|
||||
int cid, int tid);
|
||||
void wil_vring_fini_tx(struct wil6210_priv *wil, int id);
|
||||
|
||||
netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev);
|
||||
void wil_tx_complete(struct wil6210_priv *wil, int ringid);
|
||||
|
||||
/* RX API */
|
||||
void wil_rx_handle(struct wil6210_priv *wil);
|
||||
|
||||
int wil_iftype_nl2wmi(enum nl80211_iftype type);
|
||||
|
||||
#endif /* __WIL6210_H__ */
|
975
drivers/net/wireless/ath/wil6210/wmi.c
Normal file
975
drivers/net/wireless/ath/wil6210/wmi.c
Normal file
|
@ -0,0 +1,975 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Qualcomm Atheros, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/etherdevice.h>
|
||||
|
||||
#include "wil6210.h"
|
||||
#include "wmi.h"
|
||||
|
||||
/**
|
||||
* WMI event receiving - theory of operations
|
||||
*
|
||||
* When firmware about to report WMI event, it fills memory area
|
||||
* in the mailbox and raises misc. IRQ. Thread interrupt handler invoked for
|
||||
* the misc IRQ, function @wmi_recv_cmd called by thread IRQ handler.
|
||||
*
|
||||
* @wmi_recv_cmd reads event, allocates memory chunk and attaches it to the
|
||||
* event list @wil->pending_wmi_ev. Then, work queue @wil->wmi_wq wakes up
|
||||
* and handles events within the @wmi_event_worker. Every event get detached
|
||||
* from list, processed and deleted.
|
||||
*
|
||||
* Purpose for this mechanism is to release IRQ thread; otherwise,
|
||||
* if WMI event handling involves another WMI command flow, this 2-nd flow
|
||||
* won't be completed because of blocked IRQ thread.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Addressing - theory of operations
|
||||
*
|
||||
* There are several buses present on the WIL6210 card.
|
||||
* Same memory areas are visible at different address on
|
||||
* the different busses. There are 3 main bus masters:
|
||||
* - MAC CPU (ucode)
|
||||
* - User CPU (firmware)
|
||||
* - AHB (host)
|
||||
*
|
||||
* On the PCI bus, there is one BAR (BAR0) of 2Mb size, exposing
|
||||
* AHB addresses starting from 0x880000
|
||||
*
|
||||
* Internally, firmware uses addresses that allows faster access but
|
||||
* are invisible from the host. To read from these addresses, alternative
|
||||
* AHB address must be used.
|
||||
*
|
||||
* Memory mapping
|
||||
* Linker address PCI/Host address
|
||||
* 0x880000 .. 0xa80000 2Mb BAR0
|
||||
* 0x800000 .. 0x807000 0x900000 .. 0x907000 28k DCCM
|
||||
* 0x840000 .. 0x857000 0x908000 .. 0x91f000 92k PERIPH
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fw_mapping provides memory remapping table
|
||||
*/
|
||||
static const struct {
|
||||
u32 from; /* linker address - from, inclusive */
|
||||
u32 to; /* linker address - to, exclusive */
|
||||
u32 host; /* PCI/Host address - BAR0 + 0x880000 */
|
||||
} fw_mapping[] = {
|
||||
{0x000000, 0x040000, 0x8c0000}, /* FW code RAM 256k */
|
||||
{0x800000, 0x808000, 0x900000}, /* FW data RAM 32k */
|
||||
{0x840000, 0x860000, 0x908000}, /* peripheral data RAM 128k/96k used */
|
||||
{0x880000, 0x88a000, 0x880000}, /* various RGF */
|
||||
{0x8c0000, 0x932000, 0x8c0000}, /* trivial mapping for upper area */
|
||||
/*
|
||||
* 920000..930000 ucode code RAM
|
||||
* 930000..932000 ucode data RAM
|
||||
*/
|
||||
};
|
||||
|
||||
/**
|
||||
* return AHB address for given firmware/ucode internal (linker) address
|
||||
* @x - internal address
|
||||
* If address have no valid AHB mapping, return 0
|
||||
*/
|
||||
static u32 wmi_addr_remap(u32 x)
|
||||
{
|
||||
uint i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) {
|
||||
if ((x >= fw_mapping[i].from) && (x < fw_mapping[i].to))
|
||||
return x + fw_mapping[i].host - fw_mapping[i].from;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check address validity for WMI buffer; remap if needed
|
||||
* @ptr - internal (linker) fw/ucode address
|
||||
*
|
||||
* Valid buffer should be DWORD aligned
|
||||
*
|
||||
* return address for accessing buffer from the host;
|
||||
* if buffer is not valid, return NULL.
|
||||
*/
|
||||
void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_)
|
||||
{
|
||||
u32 off;
|
||||
u32 ptr = le32_to_cpu(ptr_);
|
||||
|
||||
if (ptr % 4)
|
||||
return NULL;
|
||||
|
||||
ptr = wmi_addr_remap(ptr);
|
||||
if (ptr < WIL6210_FW_HOST_OFF)
|
||||
return NULL;
|
||||
|
||||
off = HOSTADDR(ptr);
|
||||
if (off > WIL6210_MEM_SIZE - 4)
|
||||
return NULL;
|
||||
|
||||
return wil->csr + off;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check address validity
|
||||
*/
|
||||
void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr)
|
||||
{
|
||||
u32 off;
|
||||
|
||||
if (ptr % 4)
|
||||
return NULL;
|
||||
|
||||
if (ptr < WIL6210_FW_HOST_OFF)
|
||||
return NULL;
|
||||
|
||||
off = HOSTADDR(ptr);
|
||||
if (off > WIL6210_MEM_SIZE - 4)
|
||||
return NULL;
|
||||
|
||||
return wil->csr + off;
|
||||
}
|
||||
|
||||
int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr,
|
||||
struct wil6210_mbox_hdr *hdr)
|
||||
{
|
||||
void __iomem *src = wmi_buffer(wil, ptr);
|
||||
if (!src)
|
||||
return -EINVAL;
|
||||
|
||||
wil_memcpy_fromio_32(hdr, src, sizeof(*hdr));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
|
||||
{
|
||||
struct {
|
||||
struct wil6210_mbox_hdr hdr;
|
||||
struct wil6210_mbox_hdr_wmi wmi;
|
||||
} __packed cmd = {
|
||||
.hdr = {
|
||||
.type = WIL_MBOX_HDR_TYPE_WMI,
|
||||
.flags = 0,
|
||||
.len = cpu_to_le16(sizeof(cmd.wmi) + len),
|
||||
},
|
||||
.wmi = {
|
||||
.id = cpu_to_le16(cmdid),
|
||||
.info1 = 0,
|
||||
},
|
||||
};
|
||||
struct wil6210_mbox_ring *r = &wil->mbox_ctl.tx;
|
||||
struct wil6210_mbox_ring_desc d_head;
|
||||
u32 next_head;
|
||||
void __iomem *dst;
|
||||
void __iomem *head = wmi_addr(wil, r->head);
|
||||
uint retry;
|
||||
|
||||
if (sizeof(cmd) + len > r->entry_size) {
|
||||
wil_err(wil, "WMI size too large: %d bytes, max is %d\n",
|
||||
(int)(sizeof(cmd) + len), r->entry_size);
|
||||
return -ERANGE;
|
||||
|
||||
}
|
||||
|
||||
might_sleep();
|
||||
|
||||
if (!test_bit(wil_status_fwready, &wil->status)) {
|
||||
wil_err(wil, "FW not ready\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
if (!head) {
|
||||
wil_err(wil, "WMI head is garbage: 0x%08x\n", r->head);
|
||||
return -EINVAL;
|
||||
}
|
||||
/* read Tx head till it is not busy */
|
||||
for (retry = 5; retry > 0; retry--) {
|
||||
wil_memcpy_fromio_32(&d_head, head, sizeof(d_head));
|
||||
if (d_head.sync == 0)
|
||||
break;
|
||||
msleep(20);
|
||||
}
|
||||
if (d_head.sync != 0) {
|
||||
wil_err(wil, "WMI head busy\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
/* next head */
|
||||
next_head = r->base + ((r->head - r->base + sizeof(d_head)) % r->size);
|
||||
wil_dbg_WMI(wil, "Head 0x%08x -> 0x%08x\n", r->head, next_head);
|
||||
/* wait till FW finish with previous command */
|
||||
for (retry = 5; retry > 0; retry--) {
|
||||
r->tail = ioread32(wil->csr + HOST_MBOX +
|
||||
offsetof(struct wil6210_mbox_ctl, tx.tail));
|
||||
if (next_head != r->tail)
|
||||
break;
|
||||
msleep(20);
|
||||
}
|
||||
if (next_head == r->tail) {
|
||||
wil_err(wil, "WMI ring full\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
dst = wmi_buffer(wil, d_head.addr);
|
||||
if (!dst) {
|
||||
wil_err(wil, "invalid WMI buffer: 0x%08x\n",
|
||||
le32_to_cpu(d_head.addr));
|
||||
return -EINVAL;
|
||||
}
|
||||
cmd.hdr.seq = cpu_to_le16(++wil->wmi_seq);
|
||||
/* set command */
|
||||
wil_dbg_WMI(wil, "WMI command 0x%04x [%d]\n", cmdid, len);
|
||||
wil_hex_dump_WMI("Cmd ", DUMP_PREFIX_OFFSET, 16, 1, &cmd,
|
||||
sizeof(cmd), true);
|
||||
wil_hex_dump_WMI("cmd ", DUMP_PREFIX_OFFSET, 16, 1, buf,
|
||||
len, true);
|
||||
wil_memcpy_toio_32(dst, &cmd, sizeof(cmd));
|
||||
wil_memcpy_toio_32(dst + sizeof(cmd), buf, len);
|
||||
/* mark entry as full */
|
||||
iowrite32(1, wil->csr + HOSTADDR(r->head) +
|
||||
offsetof(struct wil6210_mbox_ring_desc, sync));
|
||||
/* advance next ptr */
|
||||
iowrite32(r->head = next_head, wil->csr + HOST_MBOX +
|
||||
offsetof(struct wil6210_mbox_ctl, tx.head));
|
||||
|
||||
/* interrupt to FW */
|
||||
iowrite32(SW_INT_MBOX, wil->csr + HOST_SW_INT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
|
||||
{
|
||||
int rc;
|
||||
|
||||
mutex_lock(&wil->wmi_mutex);
|
||||
rc = __wmi_send(wil, cmdid, buf, len);
|
||||
mutex_unlock(&wil->wmi_mutex);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*=== Event handlers ===*/
|
||||
static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len)
|
||||
{
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct wireless_dev *wdev = wil->wdev;
|
||||
struct wmi_ready_event *evt = d;
|
||||
u32 ver = le32_to_cpu(evt->sw_version);
|
||||
|
||||
wil_dbg_WMI(wil, "FW ver. %d; MAC %pM\n", ver, evt->mac);
|
||||
|
||||
if (!is_valid_ether_addr(ndev->dev_addr)) {
|
||||
memcpy(ndev->dev_addr, evt->mac, ETH_ALEN);
|
||||
memcpy(ndev->perm_addr, evt->mac, ETH_ALEN);
|
||||
}
|
||||
snprintf(wdev->wiphy->fw_version, sizeof(wdev->wiphy->fw_version),
|
||||
"%d", ver);
|
||||
}
|
||||
|
||||
static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d,
|
||||
int len)
|
||||
{
|
||||
wil_dbg_WMI(wil, "WMI: FW ready\n");
|
||||
|
||||
set_bit(wil_status_fwready, &wil->status);
|
||||
/* reuse wmi_ready for the firmware ready indication */
|
||||
complete(&wil->wmi_ready);
|
||||
}
|
||||
|
||||
static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
|
||||
{
|
||||
struct wmi_rx_mgmt_packet_event *data = d;
|
||||
struct wiphy *wiphy = wil_to_wiphy(wil);
|
||||
struct ieee80211_mgmt *rx_mgmt_frame =
|
||||
(struct ieee80211_mgmt *)data->payload;
|
||||
int ch_no = data->info.channel+1;
|
||||
u32 freq = ieee80211_channel_to_frequency(ch_no,
|
||||
IEEE80211_BAND_60GHZ);
|
||||
struct ieee80211_channel *channel = ieee80211_get_channel(wiphy, freq);
|
||||
/* TODO convert LE to CPU */
|
||||
s32 signal = 0; /* TODO */
|
||||
__le16 fc = rx_mgmt_frame->frame_control;
|
||||
u32 d_len = le32_to_cpu(data->info.len);
|
||||
u16 d_status = le16_to_cpu(data->info.status);
|
||||
|
||||
wil_dbg_WMI(wil, "MGMT: channel %d MCS %d SNR %d\n",
|
||||
data->info.channel, data->info.mcs, data->info.snr);
|
||||
wil_dbg_WMI(wil, "status 0x%04x len %d stype %04x\n", d_status, d_len,
|
||||
le16_to_cpu(data->info.stype));
|
||||
wil_dbg_WMI(wil, "qid %d mid %d cid %d\n",
|
||||
data->info.qid, data->info.mid, data->info.cid);
|
||||
|
||||
if (!channel) {
|
||||
wil_err(wil, "Frame on unsupported channel\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ieee80211_is_beacon(fc) || ieee80211_is_probe_resp(fc)) {
|
||||
struct cfg80211_bss *bss;
|
||||
u64 tsf = le64_to_cpu(rx_mgmt_frame->u.beacon.timestamp);
|
||||
u16 cap = le16_to_cpu(rx_mgmt_frame->u.beacon.capab_info);
|
||||
u16 bi = le16_to_cpu(rx_mgmt_frame->u.beacon.beacon_int);
|
||||
const u8 *ie_buf = rx_mgmt_frame->u.beacon.variable;
|
||||
size_t ie_len = d_len - offsetof(struct ieee80211_mgmt,
|
||||
u.beacon.variable);
|
||||
wil_dbg_WMI(wil, "Capability info : 0x%04x\n", cap);
|
||||
|
||||
bss = cfg80211_inform_bss(wiphy, channel, rx_mgmt_frame->bssid,
|
||||
tsf, cap, bi, ie_buf, ie_len,
|
||||
signal, GFP_KERNEL);
|
||||
if (bss) {
|
||||
wil_dbg_WMI(wil, "Added BSS %pM\n",
|
||||
rx_mgmt_frame->bssid);
|
||||
cfg80211_put_bss(bss);
|
||||
} else {
|
||||
wil_err(wil, "cfg80211_inform_bss() failed\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id,
|
||||
void *d, int len)
|
||||
{
|
||||
if (wil->scan_request) {
|
||||
struct wmi_scan_complete_event *data = d;
|
||||
bool aborted = (data->status != 0);
|
||||
|
||||
wil_dbg_WMI(wil, "SCAN_COMPLETE(0x%08x)\n", data->status);
|
||||
cfg80211_scan_done(wil->scan_request, aborted);
|
||||
wil->scan_request = NULL;
|
||||
} else {
|
||||
wil_err(wil, "SCAN_COMPLETE while not scanning\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
|
||||
{
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct wireless_dev *wdev = wil->wdev;
|
||||
struct wmi_connect_event *evt = d;
|
||||
int ch; /* channel number */
|
||||
struct station_info sinfo;
|
||||
u8 *assoc_req_ie, *assoc_resp_ie;
|
||||
size_t assoc_req_ielen, assoc_resp_ielen;
|
||||
/* capinfo(u16) + listen_interval(u16) + IEs */
|
||||
const size_t assoc_req_ie_offset = sizeof(u16) * 2;
|
||||
/* capinfo(u16) + status_code(u16) + associd(u16) + IEs */
|
||||
const size_t assoc_resp_ie_offset = sizeof(u16) * 3;
|
||||
|
||||
if (len < sizeof(*evt)) {
|
||||
wil_err(wil, "Connect event too short : %d bytes\n", len);
|
||||
return;
|
||||
}
|
||||
if (len != sizeof(*evt) + evt->beacon_ie_len + evt->assoc_req_len +
|
||||
evt->assoc_resp_len) {
|
||||
wil_err(wil,
|
||||
"Connect event corrupted : %d != %d + %d + %d + %d\n",
|
||||
len, (int)sizeof(*evt), evt->beacon_ie_len,
|
||||
evt->assoc_req_len, evt->assoc_resp_len);
|
||||
return;
|
||||
}
|
||||
ch = evt->channel + 1;
|
||||
wil_dbg_WMI(wil, "Connect %pM channel [%d] cid %d\n",
|
||||
evt->bssid, ch, evt->cid);
|
||||
wil_hex_dump_WMI("connect AI : ", DUMP_PREFIX_OFFSET, 16, 1,
|
||||
evt->assoc_info, len - sizeof(*evt), true);
|
||||
|
||||
/* figure out IE's */
|
||||
assoc_req_ie = &evt->assoc_info[evt->beacon_ie_len +
|
||||
assoc_req_ie_offset];
|
||||
assoc_req_ielen = evt->assoc_req_len - assoc_req_ie_offset;
|
||||
if (evt->assoc_req_len <= assoc_req_ie_offset) {
|
||||
assoc_req_ie = NULL;
|
||||
assoc_req_ielen = 0;
|
||||
}
|
||||
|
||||
assoc_resp_ie = &evt->assoc_info[evt->beacon_ie_len +
|
||||
evt->assoc_req_len +
|
||||
assoc_resp_ie_offset];
|
||||
assoc_resp_ielen = evt->assoc_resp_len - assoc_resp_ie_offset;
|
||||
if (evt->assoc_resp_len <= assoc_resp_ie_offset) {
|
||||
assoc_resp_ie = NULL;
|
||||
assoc_resp_ielen = 0;
|
||||
}
|
||||
|
||||
if ((wdev->iftype == NL80211_IFTYPE_STATION) ||
|
||||
(wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
|
||||
if (wdev->sme_state != CFG80211_SME_CONNECTING) {
|
||||
wil_err(wil, "Not in connecting state\n");
|
||||
return;
|
||||
}
|
||||
del_timer_sync(&wil->connect_timer);
|
||||
cfg80211_connect_result(ndev, evt->bssid,
|
||||
assoc_req_ie, assoc_req_ielen,
|
||||
assoc_resp_ie, assoc_resp_ielen,
|
||||
WLAN_STATUS_SUCCESS, GFP_KERNEL);
|
||||
|
||||
} else if ((wdev->iftype == NL80211_IFTYPE_AP) ||
|
||||
(wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
|
||||
memset(&sinfo, 0, sizeof(sinfo));
|
||||
|
||||
sinfo.generation = wil->sinfo_gen++;
|
||||
|
||||
if (assoc_req_ie) {
|
||||
sinfo.assoc_req_ies = assoc_req_ie;
|
||||
sinfo.assoc_req_ies_len = assoc_req_ielen;
|
||||
sinfo.filled |= STATION_INFO_ASSOC_REQ_IES;
|
||||
}
|
||||
|
||||
cfg80211_new_sta(ndev, evt->bssid, &sinfo, GFP_KERNEL);
|
||||
}
|
||||
set_bit(wil_status_fwconnected, &wil->status);
|
||||
|
||||
/* FIXME FW can transmit only ucast frames to peer */
|
||||
/* FIXME real ring_id instead of hard coded 0 */
|
||||
memcpy(wil->dst_addr[0], evt->bssid, ETH_ALEN);
|
||||
|
||||
wil->pending_connect_cid = evt->cid;
|
||||
queue_work(wil->wmi_wq_conn, &wil->wmi_connect_worker);
|
||||
}
|
||||
|
||||
static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
|
||||
void *d, int len)
|
||||
{
|
||||
struct wmi_disconnect_event *evt = d;
|
||||
|
||||
wil_dbg_WMI(wil, "Disconnect %pM reason %d proto %d wmi\n",
|
||||
evt->bssid,
|
||||
evt->protocol_reason_status, evt->disconnect_reason);
|
||||
|
||||
wil->sinfo_gen++;
|
||||
|
||||
wil6210_disconnect(wil, evt->bssid);
|
||||
clear_bit(wil_status_dontscan, &wil->status);
|
||||
}
|
||||
|
||||
static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len)
|
||||
{
|
||||
struct wmi_notify_req_done_event *evt = d;
|
||||
|
||||
if (len < sizeof(*evt)) {
|
||||
wil_err(wil, "Short NOTIFY event\n");
|
||||
return;
|
||||
}
|
||||
|
||||
wil->stats.tsf = le64_to_cpu(evt->tsf);
|
||||
wil->stats.snr = le32_to_cpu(evt->snr_val);
|
||||
wil->stats.bf_mcs = le16_to_cpu(evt->bf_mcs);
|
||||
wil->stats.my_rx_sector = le16_to_cpu(evt->my_rx_sector);
|
||||
wil->stats.my_tx_sector = le16_to_cpu(evt->my_tx_sector);
|
||||
wil->stats.peer_rx_sector = le16_to_cpu(evt->other_rx_sector);
|
||||
wil->stats.peer_tx_sector = le16_to_cpu(evt->other_tx_sector);
|
||||
wil_dbg_WMI(wil, "Link status, MCS %d TSF 0x%016llx\n"
|
||||
"BF status 0x%08x SNR 0x%08x\n"
|
||||
"Tx Tpt %d goodput %d Rx goodput %d\n"
|
||||
"Sectors(rx:tx) my %d:%d peer %d:%d\n",
|
||||
wil->stats.bf_mcs, wil->stats.tsf, evt->status,
|
||||
wil->stats.snr, le32_to_cpu(evt->tx_tpt),
|
||||
le32_to_cpu(evt->tx_goodput), le32_to_cpu(evt->rx_goodput),
|
||||
wil->stats.my_rx_sector, wil->stats.my_tx_sector,
|
||||
wil->stats.peer_rx_sector, wil->stats.peer_tx_sector);
|
||||
}
|
||||
|
||||
/*
|
||||
* Firmware reports EAPOL frame using WME event.
|
||||
* Reconstruct Ethernet frame and deliver it via normal Rx
|
||||
*/
|
||||
static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
|
||||
void *d, int len)
|
||||
{
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct wmi_eapol_rx_event *evt = d;
|
||||
u16 eapol_len = le16_to_cpu(evt->eapol_len);
|
||||
int sz = eapol_len + ETH_HLEN;
|
||||
struct sk_buff *skb;
|
||||
struct ethhdr *eth;
|
||||
|
||||
wil_dbg_WMI(wil, "EAPOL len %d from %pM\n", eapol_len,
|
||||
evt->src_mac);
|
||||
|
||||
if (eapol_len > 196) { /* TODO: revisit size limit */
|
||||
wil_err(wil, "EAPOL too large\n");
|
||||
return;
|
||||
}
|
||||
|
||||
skb = alloc_skb(sz, GFP_KERNEL);
|
||||
if (!skb) {
|
||||
wil_err(wil, "Failed to allocate skb\n");
|
||||
return;
|
||||
}
|
||||
eth = (struct ethhdr *)skb_put(skb, ETH_HLEN);
|
||||
memcpy(eth->h_dest, ndev->dev_addr, ETH_ALEN);
|
||||
memcpy(eth->h_source, evt->src_mac, ETH_ALEN);
|
||||
eth->h_proto = cpu_to_be16(ETH_P_PAE);
|
||||
memcpy(skb_put(skb, eapol_len), evt->eapol, eapol_len);
|
||||
skb->protocol = eth_type_trans(skb, ndev);
|
||||
if (likely(netif_rx_ni(skb) == NET_RX_SUCCESS)) {
|
||||
ndev->stats.rx_packets++;
|
||||
ndev->stats.rx_bytes += skb->len;
|
||||
} else {
|
||||
ndev->stats.rx_dropped++;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct {
|
||||
int eventid;
|
||||
void (*handler)(struct wil6210_priv *wil, int eventid,
|
||||
void *data, int data_len);
|
||||
} wmi_evt_handlers[] = {
|
||||
{WMI_READY_EVENTID, wmi_evt_ready},
|
||||
{WMI_FW_READY_EVENTID, wmi_evt_fw_ready},
|
||||
{WMI_RX_MGMT_PACKET_EVENTID, wmi_evt_rx_mgmt},
|
||||
{WMI_SCAN_COMPLETE_EVENTID, wmi_evt_scan_complete},
|
||||
{WMI_CONNECT_EVENTID, wmi_evt_connect},
|
||||
{WMI_DISCONNECT_EVENTID, wmi_evt_disconnect},
|
||||
{WMI_NOTIFY_REQ_DONE_EVENTID, wmi_evt_notify},
|
||||
{WMI_EAPOL_RX_EVENTID, wmi_evt_eapol_rx},
|
||||
};
|
||||
|
||||
/*
|
||||
* Run in IRQ context
|
||||
* Extract WMI command from mailbox. Queue it to the @wil->pending_wmi_ev
|
||||
* that will be eventually handled by the @wmi_event_worker in the thread
|
||||
* context of thread "wil6210_wmi"
|
||||
*/
|
||||
void wmi_recv_cmd(struct wil6210_priv *wil)
|
||||
{
|
||||
struct wil6210_mbox_ring_desc d_tail;
|
||||
struct wil6210_mbox_hdr hdr;
|
||||
struct wil6210_mbox_ring *r = &wil->mbox_ctl.rx;
|
||||
struct pending_wmi_event *evt;
|
||||
u8 *cmd;
|
||||
void __iomem *src;
|
||||
ulong flags;
|
||||
|
||||
for (;;) {
|
||||
u16 len;
|
||||
|
||||
r->head = ioread32(wil->csr + HOST_MBOX +
|
||||
offsetof(struct wil6210_mbox_ctl, rx.head));
|
||||
if (r->tail == r->head)
|
||||
return;
|
||||
|
||||
/* read cmd from tail */
|
||||
wil_memcpy_fromio_32(&d_tail, wil->csr + HOSTADDR(r->tail),
|
||||
sizeof(struct wil6210_mbox_ring_desc));
|
||||
if (d_tail.sync == 0) {
|
||||
wil_err(wil, "Mbox evt not owned by FW?\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (0 != wmi_read_hdr(wil, d_tail.addr, &hdr)) {
|
||||
wil_err(wil, "Mbox evt at 0x%08x?\n",
|
||||
le32_to_cpu(d_tail.addr));
|
||||
return;
|
||||
}
|
||||
|
||||
len = le16_to_cpu(hdr.len);
|
||||
src = wmi_buffer(wil, d_tail.addr) +
|
||||
sizeof(struct wil6210_mbox_hdr);
|
||||
evt = kmalloc(ALIGN(offsetof(struct pending_wmi_event,
|
||||
event.wmi) + len, 4),
|
||||
GFP_KERNEL);
|
||||
if (!evt) {
|
||||
wil_err(wil, "kmalloc for WMI event (%d) failed\n",
|
||||
len);
|
||||
return;
|
||||
}
|
||||
evt->event.hdr = hdr;
|
||||
cmd = (void *)&evt->event.wmi;
|
||||
wil_memcpy_fromio_32(cmd, src, len);
|
||||
/* mark entry as empty */
|
||||
iowrite32(0, wil->csr + HOSTADDR(r->tail) +
|
||||
offsetof(struct wil6210_mbox_ring_desc, sync));
|
||||
/* indicate */
|
||||
wil_dbg_WMI(wil, "Mbox evt %04x %04x %04x %02x\n",
|
||||
le16_to_cpu(hdr.seq), len, le16_to_cpu(hdr.type),
|
||||
hdr.flags);
|
||||
if ((hdr.type == WIL_MBOX_HDR_TYPE_WMI) &&
|
||||
(len >= sizeof(struct wil6210_mbox_hdr_wmi))) {
|
||||
wil_dbg_WMI(wil, "WMI event 0x%04x\n",
|
||||
evt->event.wmi.id);
|
||||
}
|
||||
wil_hex_dump_WMI("evt ", DUMP_PREFIX_OFFSET, 16, 1,
|
||||
&evt->event.hdr, sizeof(hdr) + len, true);
|
||||
|
||||
/* advance tail */
|
||||
r->tail = r->base + ((r->tail - r->base +
|
||||
sizeof(struct wil6210_mbox_ring_desc)) % r->size);
|
||||
iowrite32(r->tail, wil->csr + HOST_MBOX +
|
||||
offsetof(struct wil6210_mbox_ctl, rx.tail));
|
||||
|
||||
/* add to the pending list */
|
||||
spin_lock_irqsave(&wil->wmi_ev_lock, flags);
|
||||
list_add_tail(&evt->list, &wil->pending_wmi_ev);
|
||||
spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
|
||||
{
|
||||
int q = queue_work(wil->wmi_wq,
|
||||
&wil->wmi_event_worker);
|
||||
wil_dbg_WMI(wil, "queue_work -> %d\n", q);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
|
||||
u16 reply_id, void *reply, u8 reply_size, int to_msec)
|
||||
{
|
||||
int rc;
|
||||
int remain;
|
||||
|
||||
mutex_lock(&wil->wmi_mutex);
|
||||
|
||||
rc = __wmi_send(wil, cmdid, buf, len);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
wil->reply_id = reply_id;
|
||||
wil->reply_buf = reply;
|
||||
wil->reply_size = reply_size;
|
||||
remain = wait_for_completion_timeout(&wil->wmi_ready,
|
||||
msecs_to_jiffies(to_msec));
|
||||
if (0 == remain) {
|
||||
wil_err(wil, "wmi_call(0x%04x->0x%04x) timeout %d msec\n",
|
||||
cmdid, reply_id, to_msec);
|
||||
rc = -ETIME;
|
||||
} else {
|
||||
wil_dbg_WMI(wil,
|
||||
"wmi_call(0x%04x->0x%04x) completed in %d msec\n",
|
||||
cmdid, reply_id,
|
||||
to_msec - jiffies_to_msecs(remain));
|
||||
}
|
||||
wil->reply_id = 0;
|
||||
wil->reply_buf = NULL;
|
||||
wil->reply_size = 0;
|
||||
out:
|
||||
mutex_unlock(&wil->wmi_mutex);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int wmi_echo(struct wil6210_priv *wil)
|
||||
{
|
||||
struct wmi_echo_cmd cmd = {
|
||||
.value = cpu_to_le32(0x12345678),
|
||||
};
|
||||
|
||||
return wmi_call(wil, WMI_ECHO_CMDID, &cmd, sizeof(cmd),
|
||||
WMI_ECHO_RSP_EVENTID, NULL, 0, 20);
|
||||
}
|
||||
|
||||
int wmi_set_mac_address(struct wil6210_priv *wil, void *addr)
|
||||
{
|
||||
struct wmi_set_mac_address_cmd cmd;
|
||||
|
||||
memcpy(cmd.mac, addr, ETH_ALEN);
|
||||
|
||||
wil_dbg_WMI(wil, "Set MAC %pM\n", addr);
|
||||
|
||||
return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, &cmd, sizeof(cmd));
|
||||
}
|
||||
|
||||
int wmi_set_bcon(struct wil6210_priv *wil, int bi, u8 wmi_nettype)
|
||||
{
|
||||
struct wmi_bcon_ctrl_cmd cmd = {
|
||||
.bcon_interval = cpu_to_le16(bi),
|
||||
.network_type = wmi_nettype,
|
||||
.disable_sec_offload = 1,
|
||||
};
|
||||
|
||||
if (!wil->secure_pcp)
|
||||
cmd.disable_sec = 1;
|
||||
|
||||
return wmi_send(wil, WMI_BCON_CTRL_CMDID, &cmd, sizeof(cmd));
|
||||
}
|
||||
|
||||
int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid)
|
||||
{
|
||||
struct wmi_set_ssid_cmd cmd = {
|
||||
.ssid_len = cpu_to_le32(ssid_len),
|
||||
};
|
||||
|
||||
if (ssid_len > sizeof(cmd.ssid))
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(cmd.ssid, ssid, ssid_len);
|
||||
|
||||
return wmi_send(wil, WMI_SET_SSID_CMDID, &cmd, sizeof(cmd));
|
||||
}
|
||||
|
||||
int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid)
|
||||
{
|
||||
int rc;
|
||||
struct {
|
||||
struct wil6210_mbox_hdr_wmi wmi;
|
||||
struct wmi_set_ssid_cmd cmd;
|
||||
} __packed reply;
|
||||
int len; /* reply.cmd.ssid_len in CPU order */
|
||||
|
||||
rc = wmi_call(wil, WMI_GET_SSID_CMDID, NULL, 0, WMI_GET_SSID_EVENTID,
|
||||
&reply, sizeof(reply), 20);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
len = le32_to_cpu(reply.cmd.ssid_len);
|
||||
if (len > sizeof(reply.cmd.ssid))
|
||||
return -EINVAL;
|
||||
|
||||
*ssid_len = len;
|
||||
memcpy(ssid, reply.cmd.ssid, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wmi_set_channel(struct wil6210_priv *wil, int channel)
|
||||
{
|
||||
struct wmi_set_pcp_channel_cmd cmd = {
|
||||
.channel = channel - 1,
|
||||
};
|
||||
|
||||
return wmi_send(wil, WMI_SET_PCP_CHANNEL_CMDID, &cmd, sizeof(cmd));
|
||||
}
|
||||
|
||||
int wmi_get_channel(struct wil6210_priv *wil, int *channel)
|
||||
{
|
||||
int rc;
|
||||
struct {
|
||||
struct wil6210_mbox_hdr_wmi wmi;
|
||||
struct wmi_set_pcp_channel_cmd cmd;
|
||||
} __packed reply;
|
||||
|
||||
rc = wmi_call(wil, WMI_GET_PCP_CHANNEL_CMDID, NULL, 0,
|
||||
WMI_GET_PCP_CHANNEL_EVENTID, &reply, sizeof(reply), 20);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (reply.cmd.channel > 3)
|
||||
return -EINVAL;
|
||||
|
||||
*channel = reply.cmd.channel + 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wmi_tx_eapol(struct wil6210_priv *wil, struct sk_buff *skb)
|
||||
{
|
||||
struct wmi_eapol_tx_cmd *cmd;
|
||||
struct ethhdr *eth;
|
||||
u16 eapol_len = skb->len - ETH_HLEN;
|
||||
void *eapol = skb->data + ETH_HLEN;
|
||||
uint i;
|
||||
int rc;
|
||||
|
||||
skb_set_mac_header(skb, 0);
|
||||
eth = eth_hdr(skb);
|
||||
wil_dbg_WMI(wil, "EAPOL %d bytes to %pM\n", eapol_len, eth->h_dest);
|
||||
for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
|
||||
if (memcmp(wil->dst_addr[i], eth->h_dest, ETH_ALEN) == 0)
|
||||
goto found_dest;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
|
||||
found_dest:
|
||||
/* find out eapol data & len */
|
||||
cmd = kzalloc(sizeof(*cmd) + eapol_len, GFP_KERNEL);
|
||||
if (!cmd)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(cmd->dst_mac, eth->h_dest, ETH_ALEN);
|
||||
cmd->eapol_len = cpu_to_le16(eapol_len);
|
||||
memcpy(cmd->eapol, eapol, eapol_len);
|
||||
rc = wmi_send(wil, WMI_EAPOL_TX_CMDID, cmd, sizeof(*cmd) + eapol_len);
|
||||
kfree(cmd);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index,
|
||||
const void *mac_addr)
|
||||
{
|
||||
struct wmi_delete_cipher_key_cmd cmd = {
|
||||
.key_index = key_index,
|
||||
};
|
||||
|
||||
if (mac_addr)
|
||||
memcpy(cmd.mac, mac_addr, WMI_MAC_LEN);
|
||||
|
||||
return wmi_send(wil, WMI_DELETE_CIPHER_KEY_CMDID, &cmd, sizeof(cmd));
|
||||
}
|
||||
|
||||
int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index,
|
||||
const void *mac_addr, int key_len, const void *key)
|
||||
{
|
||||
struct wmi_add_cipher_key_cmd cmd = {
|
||||
.key_index = key_index,
|
||||
.key_usage = WMI_KEY_USE_PAIRWISE,
|
||||
.key_len = key_len,
|
||||
};
|
||||
|
||||
if (!key || (key_len > sizeof(cmd.key)))
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(cmd.key, key, key_len);
|
||||
if (mac_addr)
|
||||
memcpy(cmd.mac, mac_addr, WMI_MAC_LEN);
|
||||
|
||||
return wmi_send(wil, WMI_ADD_CIPHER_KEY_CMDID, &cmd, sizeof(cmd));
|
||||
}
|
||||
|
||||
int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie)
|
||||
{
|
||||
int rc;
|
||||
u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len;
|
||||
struct wmi_set_appie_cmd *cmd = kzalloc(len, GFP_KERNEL);
|
||||
if (!cmd) {
|
||||
wil_err(wil, "kmalloc(%d) failed\n", len);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
cmd->mgmt_frm_type = type;
|
||||
/* BUG: FW API define ieLen as u8. Will fix FW */
|
||||
cmd->ie_len = cpu_to_le16(ie_len);
|
||||
memcpy(cmd->ie_info, ie, ie_len);
|
||||
rc = wmi_send(wil, WMI_SET_APPIE_CMDID, &cmd, len);
|
||||
kfree(cmd);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void wmi_event_flush(struct wil6210_priv *wil)
|
||||
{
|
||||
struct pending_wmi_event *evt, *t;
|
||||
|
||||
wil_dbg_WMI(wil, "%s()\n", __func__);
|
||||
|
||||
list_for_each_entry_safe(evt, t, &wil->pending_wmi_ev, list) {
|
||||
list_del(&evt->list);
|
||||
kfree(evt);
|
||||
}
|
||||
}
|
||||
|
||||
static bool wmi_evt_call_handler(struct wil6210_priv *wil, int id,
|
||||
void *d, int len)
|
||||
{
|
||||
uint i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wmi_evt_handlers); i++) {
|
||||
if (wmi_evt_handlers[i].eventid == id) {
|
||||
wmi_evt_handlers[i].handler(wil, id, d, len);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void wmi_event_handle(struct wil6210_priv *wil,
|
||||
struct wil6210_mbox_hdr *hdr)
|
||||
{
|
||||
u16 len = le16_to_cpu(hdr->len);
|
||||
|
||||
if ((hdr->type == WIL_MBOX_HDR_TYPE_WMI) &&
|
||||
(len >= sizeof(struct wil6210_mbox_hdr_wmi))) {
|
||||
struct wil6210_mbox_hdr_wmi *wmi = (void *)(&hdr[1]);
|
||||
void *evt_data = (void *)(&wmi[1]);
|
||||
u16 id = le16_to_cpu(wmi->id);
|
||||
/* check if someone waits for this event */
|
||||
if (wil->reply_id && wil->reply_id == id) {
|
||||
if (wil->reply_buf) {
|
||||
memcpy(wil->reply_buf, wmi,
|
||||
min(len, wil->reply_size));
|
||||
} else {
|
||||
wmi_evt_call_handler(wil, id, evt_data,
|
||||
len - sizeof(*wmi));
|
||||
}
|
||||
wil_dbg_WMI(wil, "Complete WMI 0x%04x\n", id);
|
||||
complete(&wil->wmi_ready);
|
||||
return;
|
||||
}
|
||||
/* unsolicited event */
|
||||
/* search for handler */
|
||||
if (!wmi_evt_call_handler(wil, id, evt_data,
|
||||
len - sizeof(*wmi))) {
|
||||
wil_err(wil, "Unhandled event 0x%04x\n", id);
|
||||
}
|
||||
} else {
|
||||
wil_err(wil, "Unknown event type\n");
|
||||
print_hex_dump(KERN_ERR, "evt?? ", DUMP_PREFIX_OFFSET, 16, 1,
|
||||
hdr, sizeof(*hdr) + len, true);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve next WMI event from the pending list
|
||||
*/
|
||||
static struct list_head *next_wmi_ev(struct wil6210_priv *wil)
|
||||
{
|
||||
ulong flags;
|
||||
struct list_head *ret = NULL;
|
||||
|
||||
spin_lock_irqsave(&wil->wmi_ev_lock, flags);
|
||||
|
||||
if (!list_empty(&wil->pending_wmi_ev)) {
|
||||
ret = wil->pending_wmi_ev.next;
|
||||
list_del(ret);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handler for the WMI events
|
||||
*/
|
||||
void wmi_event_worker(struct work_struct *work)
|
||||
{
|
||||
struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
|
||||
wmi_event_worker);
|
||||
struct pending_wmi_event *evt;
|
||||
struct list_head *lh;
|
||||
|
||||
while ((lh = next_wmi_ev(wil)) != NULL) {
|
||||
evt = list_entry(lh, struct pending_wmi_event, list);
|
||||
wmi_event_handle(wil, &evt->event.hdr);
|
||||
kfree(evt);
|
||||
}
|
||||
}
|
||||
|
||||
void wmi_connect_worker(struct work_struct *work)
|
||||
{
|
||||
int rc;
|
||||
struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
|
||||
wmi_connect_worker);
|
||||
|
||||
if (wil->pending_connect_cid < 0) {
|
||||
wil_err(wil, "No connection pending\n");
|
||||
return;
|
||||
}
|
||||
|
||||
wil_dbg_WMI(wil, "Configure for connection CID %d\n",
|
||||
wil->pending_connect_cid);
|
||||
|
||||
rc = wil_vring_init_tx(wil, 0, WIL6210_TX_RING_SIZE,
|
||||
wil->pending_connect_cid, 0);
|
||||
wil->pending_connect_cid = -1;
|
||||
if (rc == 0)
|
||||
wil_link_on(wil);
|
||||
}
|
1116
drivers/net/wireless/ath/wil6210/wmi.h
Normal file
1116
drivers/net/wireless/ath/wil6210/wmi.h
Normal file
File diff suppressed because it is too large
Load diff
|
@ -7,6 +7,7 @@
|
|||
#include <linux/hw_random.h>
|
||||
#include <linux/bcma/bcma.h>
|
||||
#include <linux/ssb/ssb.h>
|
||||
#include <linux/completion.h>
|
||||
#include <net/mac80211.h>
|
||||
|
||||
#include "debugfs.h"
|
||||
|
@ -722,6 +723,10 @@ enum b43_firmware_file_type {
|
|||
struct b43_request_fw_context {
|
||||
/* The device we are requesting the fw for. */
|
||||
struct b43_wldev *dev;
|
||||
/* a completion event structure needed if this call is asynchronous */
|
||||
struct completion fw_load_complete;
|
||||
/* a pointer to the firmware object */
|
||||
const struct firmware *blob;
|
||||
/* The type of firmware to request. */
|
||||
enum b43_firmware_file_type req_type;
|
||||
/* Error messages for each firmware type. */
|
||||
|
|
|
@ -2088,11 +2088,18 @@ static void b43_print_fw_helptext(struct b43_wl *wl, bool error)
|
|||
b43warn(wl, text);
|
||||
}
|
||||
|
||||
static void b43_fw_cb(const struct firmware *firmware, void *context)
|
||||
{
|
||||
struct b43_request_fw_context *ctx = context;
|
||||
|
||||
ctx->blob = firmware;
|
||||
complete(&ctx->fw_load_complete);
|
||||
}
|
||||
|
||||
int b43_do_request_fw(struct b43_request_fw_context *ctx,
|
||||
const char *name,
|
||||
struct b43_firmware_file *fw)
|
||||
struct b43_firmware_file *fw, bool async)
|
||||
{
|
||||
const struct firmware *blob;
|
||||
struct b43_fw_header *hdr;
|
||||
u32 size;
|
||||
int err;
|
||||
|
@ -2131,11 +2138,31 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx,
|
|||
B43_WARN_ON(1);
|
||||
return -ENOSYS;
|
||||
}
|
||||
err = request_firmware(&blob, ctx->fwname, ctx->dev->dev->dev);
|
||||
if (async) {
|
||||
/* do this part asynchronously */
|
||||
init_completion(&ctx->fw_load_complete);
|
||||
err = request_firmware_nowait(THIS_MODULE, 1, ctx->fwname,
|
||||
ctx->dev->dev->dev, GFP_KERNEL,
|
||||
ctx, b43_fw_cb);
|
||||
if (err < 0) {
|
||||
pr_err("Unable to load firmware\n");
|
||||
return err;
|
||||
}
|
||||
/* stall here until fw ready */
|
||||
wait_for_completion(&ctx->fw_load_complete);
|
||||
if (ctx->blob)
|
||||
goto fw_ready;
|
||||
/* On some ARM systems, the async request will fail, but the next sync
|
||||
* request works. For this reason, we dall through here
|
||||
*/
|
||||
}
|
||||
err = request_firmware(&ctx->blob, ctx->fwname,
|
||||
ctx->dev->dev->dev);
|
||||
if (err == -ENOENT) {
|
||||
snprintf(ctx->errors[ctx->req_type],
|
||||
sizeof(ctx->errors[ctx->req_type]),
|
||||
"Firmware file \"%s\" not found\n", ctx->fwname);
|
||||
"Firmware file \"%s\" not found\n",
|
||||
ctx->fwname);
|
||||
return err;
|
||||
} else if (err) {
|
||||
snprintf(ctx->errors[ctx->req_type],
|
||||
|
@ -2144,14 +2171,15 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx,
|
|||
ctx->fwname, err);
|
||||
return err;
|
||||
}
|
||||
if (blob->size < sizeof(struct b43_fw_header))
|
||||
fw_ready:
|
||||
if (ctx->blob->size < sizeof(struct b43_fw_header))
|
||||
goto err_format;
|
||||
hdr = (struct b43_fw_header *)(blob->data);
|
||||
hdr = (struct b43_fw_header *)(ctx->blob->data);
|
||||
switch (hdr->type) {
|
||||
case B43_FW_TYPE_UCODE:
|
||||
case B43_FW_TYPE_PCM:
|
||||
size = be32_to_cpu(hdr->size);
|
||||
if (size != blob->size - sizeof(struct b43_fw_header))
|
||||
if (size != ctx->blob->size - sizeof(struct b43_fw_header))
|
||||
goto err_format;
|
||||
/* fallthrough */
|
||||
case B43_FW_TYPE_IV:
|
||||
|
@ -2162,7 +2190,7 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx,
|
|||
goto err_format;
|
||||
}
|
||||
|
||||
fw->data = blob;
|
||||
fw->data = ctx->blob;
|
||||
fw->filename = name;
|
||||
fw->type = ctx->req_type;
|
||||
|
||||
|
@ -2172,7 +2200,7 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx,
|
|||
snprintf(ctx->errors[ctx->req_type],
|
||||
sizeof(ctx->errors[ctx->req_type]),
|
||||
"Firmware file \"%s\" format error.\n", ctx->fwname);
|
||||
release_firmware(blob);
|
||||
release_firmware(ctx->blob);
|
||||
|
||||
return -EPROTO;
|
||||
}
|
||||
|
@ -2223,7 +2251,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
|
|||
goto err_no_ucode;
|
||||
}
|
||||
}
|
||||
err = b43_do_request_fw(ctx, filename, &fw->ucode);
|
||||
err = b43_do_request_fw(ctx, filename, &fw->ucode, true);
|
||||
if (err)
|
||||
goto err_load;
|
||||
|
||||
|
@ -2235,7 +2263,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
|
|||
else
|
||||
goto err_no_pcm;
|
||||
fw->pcm_request_failed = false;
|
||||
err = b43_do_request_fw(ctx, filename, &fw->pcm);
|
||||
err = b43_do_request_fw(ctx, filename, &fw->pcm, false);
|
||||
if (err == -ENOENT) {
|
||||
/* We did not find a PCM file? Not fatal, but
|
||||
* core rev <= 10 must do without hwcrypto then. */
|
||||
|
@ -2296,7 +2324,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
|
|||
default:
|
||||
goto err_no_initvals;
|
||||
}
|
||||
err = b43_do_request_fw(ctx, filename, &fw->initvals);
|
||||
err = b43_do_request_fw(ctx, filename, &fw->initvals, false);
|
||||
if (err)
|
||||
goto err_load;
|
||||
|
||||
|
@ -2355,7 +2383,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
|
|||
default:
|
||||
goto err_no_initvals;
|
||||
}
|
||||
err = b43_do_request_fw(ctx, filename, &fw->initvals_band);
|
||||
err = b43_do_request_fw(ctx, filename, &fw->initvals_band, false);
|
||||
if (err)
|
||||
goto err_load;
|
||||
|
||||
|
|
|
@ -137,9 +137,8 @@ void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on);
|
|||
|
||||
|
||||
struct b43_request_fw_context;
|
||||
int b43_do_request_fw(struct b43_request_fw_context *ctx,
|
||||
const char *name,
|
||||
struct b43_firmware_file *fw);
|
||||
int b43_do_request_fw(struct b43_request_fw_context *ctx, const char *name,
|
||||
struct b43_firmware_file *fw, bool async);
|
||||
void b43_do_release_fw(struct b43_firmware_file *fw);
|
||||
|
||||
#endif /* B43_MAIN_H_ */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
@ -450,7 +465,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;
|
||||
|
||||
|
@ -570,14 +585,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);
|
||||
|
@ -845,6 +855,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;
|
||||
|
@ -866,9 +887,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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
@ -3091,10 +3028,11 @@ brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie,
|
|||
|
||||
len = wpa_ie->len + TLV_HDR_LEN;
|
||||
data = (u8 *)wpa_ie;
|
||||
offset = 0;
|
||||
offset = TLV_HDR_LEN;
|
||||
if (!is_rsn_ie)
|
||||
offset += VS_IE_FIXED_HDR_LEN;
|
||||
offset += WPA_IE_VERSION_LEN;
|
||||
else
|
||||
offset += WPA_IE_VERSION_LEN;
|
||||
|
||||
/* check for multicast cipher suite */
|
||||
if (offset + WPA_IE_MIN_OUI_LEN > len) {
|
||||
|
@ -3703,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,
|
||||
|
@ -4329,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];
|
||||
|
@ -4382,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,
|
||||
|
@ -4455,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;
|
||||
|
||||
|
@ -4463,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;
|
||||
|
||||
|
@ -4500,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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Broadcom Corporation
|
||||
* Copyright (c) 2012 Canonical Ltd.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
@ -1408,9 +1411,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));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -1343,13 +1343,13 @@ static bool wlc_lcnphy_rx_iq_cal_gain(struct brcms_phy *pi, u16 biq1_gain,
|
|||
|
||||
wlc_lcnphy_rx_gain_override_enable(pi, true);
|
||||
wlc_lcnphy_start_tx_tone(pi, 2000, (40 >> 1), 0);
|
||||
usleep_range(500, 500);
|
||||
udelay(500);
|
||||
write_radio_reg(pi, RADIO_2064_REG112, 0);
|
||||
if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_l))
|
||||
return false;
|
||||
|
||||
wlc_lcnphy_start_tx_tone(pi, 2000, 40, 0);
|
||||
usleep_range(500, 500);
|
||||
udelay(500);
|
||||
write_radio_reg(pi, RADIO_2064_REG112, 0);
|
||||
if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_h))
|
||||
return false;
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -3273,7 +3273,7 @@ il3945_store_measurement(struct device *d, struct device_attribute *attr,
|
|||
|
||||
if (count) {
|
||||
char *p = buffer;
|
||||
strncpy(buffer, buf, min(sizeof(buffer), count));
|
||||
strlcpy(buffer, buf, sizeof(buffer));
|
||||
channel = simple_strtoul(p, NULL, 0);
|
||||
if (channel)
|
||||
params.channel = channel;
|
||||
|
@ -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;
|
||||
|
|
|
@ -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 |
|
||||
|
@ -6308,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
|
||||
|
@ -6555,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue