Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next
This commit is contained in:
Коммит
7ae9ed8d32
|
@ -91,15 +91,8 @@ config BCM47XX
|
|||
select DMA_NONCOHERENT
|
||||
select HW_HAS_PCI
|
||||
select IRQ_CPU
|
||||
select SYS_HAS_CPU_MIPS32_R1
|
||||
select SYS_SUPPORTS_32BIT_KERNEL
|
||||
select SYS_SUPPORTS_LITTLE_ENDIAN
|
||||
select SSB
|
||||
select SSB_DRIVER_MIPS
|
||||
select SSB_DRIVER_EXTIF
|
||||
select SSB_EMBEDDED
|
||||
select SSB_B43_PCI_BRIDGE if PCI
|
||||
select SSB_PCICORE_HOSTMODE if PCI
|
||||
select GENERIC_GPIO
|
||||
select SYS_HAS_EARLY_PRINTK
|
||||
select CFE
|
||||
|
@ -788,6 +781,7 @@ endchoice
|
|||
|
||||
source "arch/mips/alchemy/Kconfig"
|
||||
source "arch/mips/ath79/Kconfig"
|
||||
source "arch/mips/bcm47xx/Kconfig"
|
||||
source "arch/mips/bcm63xx/Kconfig"
|
||||
source "arch/mips/jazz/Kconfig"
|
||||
source "arch/mips/jz4740/Kconfig"
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
if BCM47XX
|
||||
|
||||
config BCM47XX_SSB
|
||||
bool "SSB Support for Broadcom BCM47XX"
|
||||
select SYS_HAS_CPU_MIPS32_R1
|
||||
select SSB
|
||||
select SSB_DRIVER_MIPS
|
||||
select SSB_DRIVER_EXTIF
|
||||
select SSB_EMBEDDED
|
||||
select SSB_B43_PCI_BRIDGE if PCI
|
||||
select SSB_PCICORE_HOSTMODE if PCI
|
||||
default y
|
||||
help
|
||||
Add support for old Broadcom BCM47xx boards with Sonics Silicon Backplane support.
|
||||
|
||||
This will generate an image with support for SSB and MIPS32 R1 instruction set.
|
||||
|
||||
config BCM47XX_BCMA
|
||||
bool "BCMA Support for Broadcom BCM47XX"
|
||||
select SYS_HAS_CPU_MIPS32_R2
|
||||
select BCMA
|
||||
select BCMA_HOST_SOC
|
||||
select BCMA_DRIVER_MIPS
|
||||
select BCMA_DRIVER_PCI_HOSTMODE if PCI
|
||||
default y
|
||||
help
|
||||
Add support for new Broadcom BCM47xx boards with Broadcom specific Advanced Microcontroller Bus.
|
||||
|
||||
This will generate an image with support for BCMA and MIPS32 R2 instruction set.
|
||||
|
||||
endif
|
|
@ -3,4 +3,5 @@
|
|||
# under Linux.
|
||||
#
|
||||
|
||||
obj-y := gpio.o irq.o nvram.o prom.o serial.o setup.o time.o wgt634u.o
|
||||
obj-y += gpio.o irq.o nvram.o prom.o serial.o setup.o time.o
|
||||
obj-$(CONFIG_BCM47XX_SSB) += wgt634u.o
|
||||
|
|
|
@ -20,11 +20,14 @@ static DECLARE_BITMAP(gpio_in_use, BCM47XX_EXTIF_GPIO_LINES);
|
|||
|
||||
int gpio_request(unsigned gpio, const char *tag)
|
||||
{
|
||||
if (ssb_chipco_available(&ssb_bcm47xx.chipco) &&
|
||||
switch (bcm47xx_bus_type) {
|
||||
#ifdef CONFIG_BCM47XX_SSB
|
||||
case BCM47XX_BUS_TYPE_SSB:
|
||||
if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco) &&
|
||||
((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
|
||||
return -EINVAL;
|
||||
|
||||
if (ssb_extif_available(&ssb_bcm47xx.extif) &&
|
||||
if (ssb_extif_available(&bcm47xx_bus.ssb.extif) &&
|
||||
((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -32,30 +35,67 @@ int gpio_request(unsigned gpio, const char *tag)
|
|||
return -EBUSY;
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
#ifdef CONFIG_BCM47XX_BCMA
|
||||
case BCM47XX_BUS_TYPE_BCMA:
|
||||
if (gpio >= BCM47XX_CHIPCO_GPIO_LINES)
|
||||
return -EINVAL;
|
||||
|
||||
if (test_and_set_bit(gpio, gpio_in_use))
|
||||
return -EBUSY;
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_request);
|
||||
|
||||
void gpio_free(unsigned gpio)
|
||||
{
|
||||
if (ssb_chipco_available(&ssb_bcm47xx.chipco) &&
|
||||
switch (bcm47xx_bus_type) {
|
||||
#ifdef CONFIG_BCM47XX_SSB
|
||||
case BCM47XX_BUS_TYPE_SSB:
|
||||
if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco) &&
|
||||
((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
|
||||
return;
|
||||
|
||||
if (ssb_extif_available(&ssb_bcm47xx.extif) &&
|
||||
if (ssb_extif_available(&bcm47xx_bus.ssb.extif) &&
|
||||
((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
|
||||
return;
|
||||
|
||||
clear_bit(gpio, gpio_in_use);
|
||||
return;
|
||||
#endif
|
||||
#ifdef CONFIG_BCM47XX_BCMA
|
||||
case BCM47XX_BUS_TYPE_BCMA:
|
||||
if (gpio >= BCM47XX_CHIPCO_GPIO_LINES)
|
||||
return;
|
||||
|
||||
clear_bit(gpio, gpio_in_use);
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_free);
|
||||
|
||||
int gpio_to_irq(unsigned gpio)
|
||||
{
|
||||
if (ssb_chipco_available(&ssb_bcm47xx.chipco))
|
||||
return ssb_mips_irq(ssb_bcm47xx.chipco.dev) + 2;
|
||||
else if (ssb_extif_available(&ssb_bcm47xx.extif))
|
||||
return ssb_mips_irq(ssb_bcm47xx.extif.dev) + 2;
|
||||
switch (bcm47xx_bus_type) {
|
||||
#ifdef CONFIG_BCM47XX_SSB
|
||||
case BCM47XX_BUS_TYPE_SSB:
|
||||
if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco))
|
||||
return ssb_mips_irq(bcm47xx_bus.ssb.chipco.dev) + 2;
|
||||
else if (ssb_extif_available(&bcm47xx_bus.ssb.extif))
|
||||
return ssb_mips_irq(bcm47xx_bus.ssb.extif.dev) + 2;
|
||||
else
|
||||
return -EINVAL;
|
||||
#endif
|
||||
#ifdef CONFIG_BCM47XX_BCMA
|
||||
case BCM47XX_BUS_TYPE_BCMA:
|
||||
return bcma_core_mips_irq(bcm47xx_bus.bcma.bus.drv_cc.core) + 2;
|
||||
#endif
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpio_to_irq);
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <asm/irq_cpu.h>
|
||||
#include <bcm47xx.h>
|
||||
|
||||
void plat_irq_dispatch(void)
|
||||
{
|
||||
|
@ -51,5 +52,16 @@ void plat_irq_dispatch(void)
|
|||
|
||||
void __init arch_init_irq(void)
|
||||
{
|
||||
#ifdef CONFIG_BCM47XX_BCMA
|
||||
if (bcm47xx_bus_type == BCM47XX_BUS_TYPE_BCMA) {
|
||||
bcma_write32(bcm47xx_bus.bcma.bus.drv_mips.core,
|
||||
BCMA_MIPS_MIPS74K_INTMASK(5), 1 << 31);
|
||||
/*
|
||||
* the kernel reads the timer irq from some register and thinks
|
||||
* it's #5, but we offset it by 2 and route to #7
|
||||
*/
|
||||
cp0_compare_irq = 7;
|
||||
}
|
||||
#endif
|
||||
mips_cpu_irq_init();
|
||||
}
|
||||
|
|
|
@ -26,14 +26,35 @@ static char nvram_buf[NVRAM_SPACE];
|
|||
/* Probe for NVRAM header */
|
||||
static void early_nvram_init(void)
|
||||
{
|
||||
struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
|
||||
#ifdef CONFIG_BCM47XX_SSB
|
||||
struct ssb_mipscore *mcore_ssb;
|
||||
#endif
|
||||
#ifdef CONFIG_BCM47XX_BCMA
|
||||
struct bcma_drv_cc *bcma_cc;
|
||||
#endif
|
||||
struct nvram_header *header;
|
||||
int i;
|
||||
u32 base, lim, off;
|
||||
u32 base = 0;
|
||||
u32 lim = 0;
|
||||
u32 off;
|
||||
u32 *src, *dst;
|
||||
|
||||
base = mcore->flash_window;
|
||||
lim = mcore->flash_window_size;
|
||||
switch (bcm47xx_bus_type) {
|
||||
#ifdef CONFIG_BCM47XX_SSB
|
||||
case BCM47XX_BUS_TYPE_SSB:
|
||||
mcore_ssb = &bcm47xx_bus.ssb.mipscore;
|
||||
base = mcore_ssb->flash_window;
|
||||
lim = mcore_ssb->flash_window_size;
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_BCM47XX_BCMA
|
||||
case BCM47XX_BUS_TYPE_BCMA:
|
||||
bcma_cc = &bcm47xx_bus.bcma.bus.drv_cc;
|
||||
base = bcma_cc->pflash.window;
|
||||
lim = bcma_cc->pflash.window_size;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
off = FLASH_MIN;
|
||||
while (off <= lim) {
|
||||
|
|
|
@ -23,10 +23,11 @@ static struct platform_device uart8250_device = {
|
|||
},
|
||||
};
|
||||
|
||||
static int __init uart8250_init(void)
|
||||
#ifdef CONFIG_BCM47XX_SSB
|
||||
static int __init uart8250_init_ssb(void)
|
||||
{
|
||||
int i;
|
||||
struct ssb_mipscore *mcore = &(ssb_bcm47xx.mipscore);
|
||||
struct ssb_mipscore *mcore = &(bcm47xx_bus.ssb.mipscore);
|
||||
|
||||
memset(&uart8250_data, 0, sizeof(uart8250_data));
|
||||
|
||||
|
@ -44,6 +45,47 @@ static int __init uart8250_init(void)
|
|||
}
|
||||
return platform_device_register(&uart8250_device);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BCM47XX_BCMA
|
||||
static int __init uart8250_init_bcma(void)
|
||||
{
|
||||
int i;
|
||||
struct bcma_drv_cc *cc = &(bcm47xx_bus.bcma.bus.drv_cc);
|
||||
|
||||
memset(&uart8250_data, 0, sizeof(uart8250_data));
|
||||
|
||||
for (i = 0; i < cc->nr_serial_ports; i++) {
|
||||
struct plat_serial8250_port *p = &(uart8250_data[i]);
|
||||
struct bcma_serial_port *bcma_port;
|
||||
bcma_port = &(cc->serial_ports[i]);
|
||||
|
||||
p->mapbase = (unsigned int) bcma_port->regs;
|
||||
p->membase = (void *) bcma_port->regs;
|
||||
p->irq = bcma_port->irq + 2;
|
||||
p->uartclk = bcma_port->baud_base;
|
||||
p->regshift = bcma_port->reg_shift;
|
||||
p->iotype = UPIO_MEM;
|
||||
p->flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
|
||||
}
|
||||
return platform_device_register(&uart8250_device);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __init uart8250_init(void)
|
||||
{
|
||||
switch (bcm47xx_bus_type) {
|
||||
#ifdef CONFIG_BCM47XX_SSB
|
||||
case BCM47XX_BUS_TYPE_SSB:
|
||||
return uart8250_init_ssb();
|
||||
#endif
|
||||
#ifdef CONFIG_BCM47XX_BCMA
|
||||
case BCM47XX_BUS_TYPE_BCMA:
|
||||
return uart8250_init_bcma();
|
||||
#endif
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
module_init(uart8250_init);
|
||||
|
||||
|
|
|
@ -29,21 +29,36 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/ssb/ssb.h>
|
||||
#include <linux/ssb/ssb_embedded.h>
|
||||
#include <linux/bcma/bcma_soc.h>
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/reboot.h>
|
||||
#include <asm/time.h>
|
||||
#include <bcm47xx.h>
|
||||
#include <asm/mach-bcm47xx/nvram.h>
|
||||
|
||||
struct ssb_bus ssb_bcm47xx;
|
||||
EXPORT_SYMBOL(ssb_bcm47xx);
|
||||
union bcm47xx_bus bcm47xx_bus;
|
||||
EXPORT_SYMBOL(bcm47xx_bus);
|
||||
|
||||
enum bcm47xx_bus_type bcm47xx_bus_type;
|
||||
EXPORT_SYMBOL(bcm47xx_bus_type);
|
||||
|
||||
static void bcm47xx_machine_restart(char *command)
|
||||
{
|
||||
printk(KERN_ALERT "Please stand by while rebooting the system...\n");
|
||||
local_irq_disable();
|
||||
/* Set the watchdog timer to reset immediately */
|
||||
ssb_watchdog_timer_set(&ssb_bcm47xx, 1);
|
||||
switch (bcm47xx_bus_type) {
|
||||
#ifdef CONFIG_BCM47XX_SSB
|
||||
case BCM47XX_BUS_TYPE_SSB:
|
||||
ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 1);
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_BCM47XX_BCMA
|
||||
case BCM47XX_BUS_TYPE_BCMA:
|
||||
bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 1);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
while (1)
|
||||
cpu_relax();
|
||||
}
|
||||
|
@ -52,11 +67,23 @@ static void bcm47xx_machine_halt(void)
|
|||
{
|
||||
/* Disable interrupts and watchdog and spin forever */
|
||||
local_irq_disable();
|
||||
ssb_watchdog_timer_set(&ssb_bcm47xx, 0);
|
||||
switch (bcm47xx_bus_type) {
|
||||
#ifdef CONFIG_BCM47XX_SSB
|
||||
case BCM47XX_BUS_TYPE_SSB:
|
||||
ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_BCM47XX_BCMA
|
||||
case BCM47XX_BUS_TYPE_BCMA:
|
||||
bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 0);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
while (1)
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BCM47XX_SSB
|
||||
#define READ_FROM_NVRAM(_outvar, name, buf) \
|
||||
if (nvram_getprefix(prefix, name, buf, sizeof(buf)) >= 0)\
|
||||
sprom->_outvar = simple_strtoul(buf, NULL, 0);
|
||||
|
@ -247,7 +274,7 @@ static int bcm47xx_get_invariants(struct ssb_bus *bus,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void __init plat_mem_setup(void)
|
||||
static void __init bcm47xx_register_ssb(void)
|
||||
{
|
||||
int err;
|
||||
char buf[100];
|
||||
|
@ -258,12 +285,12 @@ void __init plat_mem_setup(void)
|
|||
printk(KERN_WARNING "bcm47xx: someone else already registered"
|
||||
" a ssb SPROM callback handler (err %d)\n", err);
|
||||
|
||||
err = ssb_bus_ssbbus_register(&ssb_bcm47xx, SSB_ENUM_BASE,
|
||||
err = ssb_bus_ssbbus_register(&(bcm47xx_bus.ssb), SSB_ENUM_BASE,
|
||||
bcm47xx_get_invariants);
|
||||
if (err)
|
||||
panic("Failed to initialize SSB bus (err %d)\n", err);
|
||||
|
||||
mcore = &ssb_bcm47xx.mipscore;
|
||||
mcore = &bcm47xx_bus.ssb.mipscore;
|
||||
if (nvram_getenv("kernel_args", buf, sizeof(buf)) >= 0) {
|
||||
if (strstr(buf, "console=ttyS1")) {
|
||||
struct ssb_serial_port port;
|
||||
|
@ -276,8 +303,57 @@ void __init plat_mem_setup(void)
|
|||
memcpy(&mcore->serial_ports[1], &port, sizeof(port));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BCM47XX_BCMA
|
||||
static void __init bcm47xx_register_bcma(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bcma_host_soc_register(&bcm47xx_bus.bcma);
|
||||
if (err)
|
||||
panic("Failed to initialize BCMA bus (err %d)\n", err);
|
||||
}
|
||||
#endif
|
||||
|
||||
void __init plat_mem_setup(void)
|
||||
{
|
||||
struct cpuinfo_mips *c = ¤t_cpu_data;
|
||||
|
||||
if (c->cputype == CPU_74K) {
|
||||
printk(KERN_INFO "bcm47xx: using bcma bus\n");
|
||||
#ifdef CONFIG_BCM47XX_BCMA
|
||||
bcm47xx_bus_type = BCM47XX_BUS_TYPE_BCMA;
|
||||
bcm47xx_register_bcma();
|
||||
#endif
|
||||
} else {
|
||||
printk(KERN_INFO "bcm47xx: using ssb bus\n");
|
||||
#ifdef CONFIG_BCM47XX_SSB
|
||||
bcm47xx_bus_type = BCM47XX_BUS_TYPE_SSB;
|
||||
bcm47xx_register_ssb();
|
||||
#endif
|
||||
}
|
||||
|
||||
_machine_restart = bcm47xx_machine_restart;
|
||||
_machine_halt = bcm47xx_machine_halt;
|
||||
pm_power_off = bcm47xx_machine_halt;
|
||||
}
|
||||
|
||||
static int __init bcm47xx_register_bus_complete(void)
|
||||
{
|
||||
switch (bcm47xx_bus_type) {
|
||||
#ifdef CONFIG_BCM47XX_SSB
|
||||
case BCM47XX_BUS_TYPE_SSB:
|
||||
/* Nothing to do */
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_BCM47XX_BCMA
|
||||
case BCM47XX_BUS_TYPE_BCMA:
|
||||
bcma_bus_register(&bcm47xx_bus.bcma.bus);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
device_initcall(bcm47xx_register_bus_complete);
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
void __init plat_time_init(void)
|
||||
{
|
||||
unsigned long hz;
|
||||
unsigned long hz = 0;
|
||||
|
||||
/*
|
||||
* Use deterministic values for initial counter interrupt
|
||||
|
@ -39,7 +39,19 @@ void __init plat_time_init(void)
|
|||
write_c0_count(0);
|
||||
write_c0_compare(0xffff);
|
||||
|
||||
hz = ssb_cpu_clock(&ssb_bcm47xx.mipscore) / 2;
|
||||
switch (bcm47xx_bus_type) {
|
||||
#ifdef CONFIG_BCM47XX_SSB
|
||||
case BCM47XX_BUS_TYPE_SSB:
|
||||
hz = ssb_cpu_clock(&bcm47xx_bus.ssb.mipscore) / 2;
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_BCM47XX_BCMA
|
||||
case BCM47XX_BUS_TYPE_BCMA:
|
||||
hz = bcma_cpu_clock(&bcm47xx_bus.bcma.bus.drv_mips) / 2;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!hz)
|
||||
hz = 100000000;
|
||||
|
||||
|
|
|
@ -108,7 +108,7 @@ static irqreturn_t gpio_interrupt(int irq, void *ignored)
|
|||
|
||||
/* Interrupts are shared, check if the current one is
|
||||
a GPIO interrupt. */
|
||||
if (!ssb_chipco_irq_status(&ssb_bcm47xx.chipco,
|
||||
if (!ssb_chipco_irq_status(&bcm47xx_bus.ssb.chipco,
|
||||
SSB_CHIPCO_IRQ_GPIO))
|
||||
return IRQ_NONE;
|
||||
|
||||
|
@ -132,22 +132,26 @@ static int __init wgt634u_init(void)
|
|||
* machine. Use the MAC address as an heuristic. Netgear Inc. has
|
||||
* been allocated ranges 00:09:5b:xx:xx:xx and 00:0f:b5:xx:xx:xx.
|
||||
*/
|
||||
u8 *et0mac;
|
||||
|
||||
u8 *et0mac = ssb_bcm47xx.sprom.et0mac;
|
||||
if (bcm47xx_bus_type != BCM47XX_BUS_TYPE_SSB)
|
||||
return -ENODEV;
|
||||
|
||||
et0mac = bcm47xx_bus.ssb.sprom.et0mac;
|
||||
|
||||
if (et0mac[0] == 0x00 &&
|
||||
((et0mac[1] == 0x09 && et0mac[2] == 0x5b) ||
|
||||
(et0mac[1] == 0x0f && et0mac[2] == 0xb5))) {
|
||||
struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
|
||||
struct ssb_mipscore *mcore = &bcm47xx_bus.ssb.mipscore;
|
||||
|
||||
printk(KERN_INFO "WGT634U machine detected.\n");
|
||||
|
||||
if (!request_irq(gpio_to_irq(WGT634U_GPIO_RESET),
|
||||
gpio_interrupt, IRQF_SHARED,
|
||||
"WGT634U GPIO", &ssb_bcm47xx.chipco)) {
|
||||
"WGT634U GPIO", &bcm47xx_bus.ssb.chipco)) {
|
||||
gpio_direction_input(WGT634U_GPIO_RESET);
|
||||
gpio_intmask(WGT634U_GPIO_RESET, 1);
|
||||
ssb_chipco_irq_mask(&ssb_bcm47xx.chipco,
|
||||
ssb_chipco_irq_mask(&bcm47xx_bus.ssb.chipco,
|
||||
SSB_CHIPCO_IRQ_GPIO,
|
||||
SSB_CHIPCO_IRQ_GPIO);
|
||||
}
|
||||
|
|
|
@ -19,7 +19,29 @@
|
|||
#ifndef __ASM_BCM47XX_H
|
||||
#define __ASM_BCM47XX_H
|
||||
|
||||
/* SSB bus */
|
||||
extern struct ssb_bus ssb_bcm47xx;
|
||||
#include <linux/ssb/ssb.h>
|
||||
#include <linux/bcma/bcma.h>
|
||||
#include <linux/bcma/bcma_soc.h>
|
||||
|
||||
enum bcm47xx_bus_type {
|
||||
#ifdef CONFIG_BCM47XX_SSB
|
||||
BCM47XX_BUS_TYPE_SSB,
|
||||
#endif
|
||||
#ifdef CONFIG_BCM47XX_BCMA
|
||||
BCM47XX_BUS_TYPE_BCMA,
|
||||
#endif
|
||||
};
|
||||
|
||||
union bcm47xx_bus {
|
||||
#ifdef CONFIG_BCM47XX_SSB
|
||||
struct ssb_bus ssb;
|
||||
#endif
|
||||
#ifdef CONFIG_BCM47XX_BCMA
|
||||
struct bcma_soc bcma;
|
||||
#endif
|
||||
};
|
||||
|
||||
extern union bcm47xx_bus bcm47xx_bus;
|
||||
extern enum bcm47xx_bus_type bcm47xx_bus_type;
|
||||
|
||||
#endif /* __ASM_BCM47XX_H */
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#define __BCM47XX_GPIO_H
|
||||
|
||||
#include <linux/ssb/ssb_embedded.h>
|
||||
#include <linux/bcma/bcma.h>
|
||||
#include <asm/mach-bcm47xx/bcm47xx.h>
|
||||
|
||||
#define BCM47XX_EXTIF_GPIO_LINES 5
|
||||
|
@ -21,41 +22,118 @@ extern int gpio_to_irq(unsigned gpio);
|
|||
|
||||
static inline int gpio_get_value(unsigned gpio)
|
||||
{
|
||||
return ssb_gpio_in(&ssb_bcm47xx, 1 << gpio);
|
||||
switch (bcm47xx_bus_type) {
|
||||
#ifdef CONFIG_BCM47XX_SSB
|
||||
case BCM47XX_BUS_TYPE_SSB:
|
||||
return ssb_gpio_in(&bcm47xx_bus.ssb, 1 << gpio);
|
||||
#endif
|
||||
#ifdef CONFIG_BCM47XX_BCMA
|
||||
case BCM47XX_BUS_TYPE_BCMA:
|
||||
return bcma_chipco_gpio_in(&bcm47xx_bus.bcma.bus.drv_cc,
|
||||
1 << gpio);
|
||||
#endif
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline void gpio_set_value(unsigned gpio, int value)
|
||||
{
|
||||
ssb_gpio_out(&ssb_bcm47xx, 1 << gpio, value ? 1 << gpio : 0);
|
||||
switch (bcm47xx_bus_type) {
|
||||
#ifdef CONFIG_BCM47XX_SSB
|
||||
case BCM47XX_BUS_TYPE_SSB:
|
||||
ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio,
|
||||
value ? 1 << gpio : 0);
|
||||
return;
|
||||
#endif
|
||||
#ifdef CONFIG_BCM47XX_BCMA
|
||||
case BCM47XX_BUS_TYPE_BCMA:
|
||||
bcma_chipco_gpio_out(&bcm47xx_bus.bcma.bus.drv_cc, 1 << gpio,
|
||||
value ? 1 << gpio : 0);
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static inline int gpio_direction_input(unsigned gpio)
|
||||
{
|
||||
ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 0);
|
||||
switch (bcm47xx_bus_type) {
|
||||
#ifdef CONFIG_BCM47XX_SSB
|
||||
case BCM47XX_BUS_TYPE_SSB:
|
||||
ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 0);
|
||||
return 0;
|
||||
#endif
|
||||
#ifdef CONFIG_BCM47XX_BCMA
|
||||
case BCM47XX_BUS_TYPE_BCMA:
|
||||
bcma_chipco_gpio_outen(&bcm47xx_bus.bcma.bus.drv_cc, 1 << gpio,
|
||||
0);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int gpio_direction_output(unsigned gpio, int value)
|
||||
{
|
||||
switch (bcm47xx_bus_type) {
|
||||
#ifdef CONFIG_BCM47XX_SSB
|
||||
case BCM47XX_BUS_TYPE_SSB:
|
||||
/* first set the gpio out value */
|
||||
ssb_gpio_out(&ssb_bcm47xx, 1 << gpio, value ? 1 << gpio : 0);
|
||||
ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio,
|
||||
value ? 1 << gpio : 0);
|
||||
/* then set the gpio mode */
|
||||
ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 1 << gpio);
|
||||
ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 1 << gpio);
|
||||
return 0;
|
||||
#endif
|
||||
#ifdef CONFIG_BCM47XX_BCMA
|
||||
case BCM47XX_BUS_TYPE_BCMA:
|
||||
/* first set the gpio out value */
|
||||
bcma_chipco_gpio_out(&bcm47xx_bus.bcma.bus.drv_cc, 1 << gpio,
|
||||
value ? 1 << gpio : 0);
|
||||
/* then set the gpio mode */
|
||||
bcma_chipco_gpio_outen(&bcm47xx_bus.bcma.bus.drv_cc, 1 << gpio,
|
||||
1 << gpio);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int gpio_intmask(unsigned gpio, int value)
|
||||
{
|
||||
ssb_gpio_intmask(&ssb_bcm47xx, 1 << gpio,
|
||||
switch (bcm47xx_bus_type) {
|
||||
#ifdef CONFIG_BCM47XX_SSB
|
||||
case BCM47XX_BUS_TYPE_SSB:
|
||||
ssb_gpio_intmask(&bcm47xx_bus.ssb, 1 << gpio,
|
||||
value ? 1 << gpio : 0);
|
||||
return 0;
|
||||
#endif
|
||||
#ifdef CONFIG_BCM47XX_BCMA
|
||||
case BCM47XX_BUS_TYPE_BCMA:
|
||||
bcma_chipco_gpio_intmask(&bcm47xx_bus.bcma.bus.drv_cc,
|
||||
1 << gpio, value ? 1 << gpio : 0);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int gpio_polarity(unsigned gpio, int value)
|
||||
{
|
||||
ssb_gpio_polarity(&ssb_bcm47xx, 1 << gpio,
|
||||
switch (bcm47xx_bus_type) {
|
||||
#ifdef CONFIG_BCM47XX_SSB
|
||||
case BCM47XX_BUS_TYPE_SSB:
|
||||
ssb_gpio_polarity(&bcm47xx_bus.ssb, 1 << gpio,
|
||||
value ? 1 << gpio : 0);
|
||||
return 0;
|
||||
#endif
|
||||
#ifdef CONFIG_BCM47XX_BCMA
|
||||
case BCM47XX_BUS_TYPE_BCMA:
|
||||
bcma_chipco_gpio_polarity(&bcm47xx_bus.bcma.bus.drv_cc,
|
||||
1 << gpio, value ? 1 << gpio : 0);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/ssb/ssb.h>
|
||||
#include <bcm47xx.h>
|
||||
|
||||
int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
||||
{
|
||||
|
@ -33,9 +34,13 @@ int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
|||
|
||||
int pcibios_plat_dev_init(struct pci_dev *dev)
|
||||
{
|
||||
#ifdef CONFIG_BCM47XX_SSB
|
||||
int res;
|
||||
u8 slot, pin;
|
||||
|
||||
if (bcm47xx_bus_type != BCM47XX_BUS_TYPE_SSB)
|
||||
return 0;
|
||||
|
||||
res = ssb_pcibios_plat_dev_init(dev);
|
||||
if (res < 0) {
|
||||
printk(KERN_ALERT "PCI: Failed to init device %s\n",
|
||||
|
@ -55,5 +60,6 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
|
|||
}
|
||||
|
||||
dev->irq = res;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -33,6 +33,19 @@ config BCMA_DRIVER_PCI_HOSTMODE
|
|||
help
|
||||
PCI core hostmode operation (external PCI bus).
|
||||
|
||||
config BCMA_HOST_SOC
|
||||
bool
|
||||
depends on BCMA_DRIVER_MIPS
|
||||
|
||||
config BCMA_DRIVER_MIPS
|
||||
bool "BCMA Broadcom MIPS core driver"
|
||||
depends on BCMA && MIPS
|
||||
help
|
||||
Driver for the Broadcom MIPS core attached to Broadcom specific
|
||||
Advanced Microcontroller Bus.
|
||||
|
||||
If unsure, say N
|
||||
|
||||
config BCMA_DEBUG
|
||||
bool "BCMA debugging"
|
||||
depends on BCMA
|
||||
|
|
|
@ -2,7 +2,9 @@ bcma-y += main.o scan.o core.o sprom.o
|
|||
bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o
|
||||
bcma-y += driver_pci.o
|
||||
bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE) += driver_pci_host.o
|
||||
bcma-$(CONFIG_BCMA_DRIVER_MIPS) += driver_mips.o
|
||||
bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o
|
||||
bcma-$(CONFIG_BCMA_HOST_SOC) += host_soc.o
|
||||
obj-$(CONFIG_BCMA) += bcma.o
|
||||
|
||||
ccflags-$(CONFIG_BCMA_DEBUG) := -DDEBUG
|
||||
|
|
|
@ -15,13 +15,29 @@ struct bcma_bus;
|
|||
/* main.c */
|
||||
int bcma_bus_register(struct bcma_bus *bus);
|
||||
void bcma_bus_unregister(struct bcma_bus *bus);
|
||||
int __init bcma_bus_early_register(struct bcma_bus *bus,
|
||||
struct bcma_device *core_cc,
|
||||
struct bcma_device *core_mips);
|
||||
|
||||
/* scan.c */
|
||||
int bcma_bus_scan(struct bcma_bus *bus);
|
||||
int __init bcma_bus_scan_early(struct bcma_bus *bus,
|
||||
struct bcma_device_id *match,
|
||||
struct bcma_device *core);
|
||||
void bcma_init_bus(struct bcma_bus *bus);
|
||||
|
||||
/* sprom.c */
|
||||
int bcma_sprom_get(struct bcma_bus *bus);
|
||||
|
||||
/* driver_chipcommon.c */
|
||||
#ifdef CONFIG_BCMA_DRIVER_MIPS
|
||||
void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
|
||||
#endif /* CONFIG_BCMA_DRIVER_MIPS */
|
||||
|
||||
/* driver_chipcommon_pmu.c */
|
||||
u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc);
|
||||
u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc);
|
||||
|
||||
#ifdef CONFIG_BCMA_HOST_PCI
|
||||
/* host_pci.c */
|
||||
extern int __init bcma_host_pci_init(void);
|
||||
|
|
|
@ -110,6 +110,8 @@ EXPORT_SYMBOL_GPL(bcma_core_pll_ctl);
|
|||
u32 bcma_core_dma_translation(struct bcma_device *core)
|
||||
{
|
||||
switch (core->bus->hosttype) {
|
||||
case BCMA_HOSTTYPE_SOC:
|
||||
return 0;
|
||||
case BCMA_HOSTTYPE_PCI:
|
||||
if (bcma_aread32(core, BCMA_IOST) & BCMA_IOST_DMA64)
|
||||
return BCMA_DMA_TRANSLATION_DMA64_CMT;
|
||||
|
|
|
@ -26,6 +26,9 @@ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
|
|||
u32 leddc_on = 10;
|
||||
u32 leddc_off = 90;
|
||||
|
||||
if (cc->setup_done)
|
||||
return;
|
||||
|
||||
if (cc->core->id.rev >= 11)
|
||||
cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
|
||||
cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP);
|
||||
|
@ -52,6 +55,8 @@ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
|
|||
((leddc_on << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) |
|
||||
(leddc_off << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT)));
|
||||
}
|
||||
|
||||
cc->setup_done = true;
|
||||
}
|
||||
|
||||
/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
|
||||
|
@ -101,3 +106,51 @@ u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value)
|
|||
{
|
||||
return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BCMA_DRIVER_MIPS
|
||||
void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
|
||||
{
|
||||
unsigned int irq;
|
||||
u32 baud_base;
|
||||
u32 i;
|
||||
unsigned int ccrev = cc->core->id.rev;
|
||||
struct bcma_serial_port *ports = cc->serial_ports;
|
||||
|
||||
if (ccrev >= 11 && ccrev != 15) {
|
||||
/* Fixed ALP clock */
|
||||
baud_base = bcma_pmu_alp_clock(cc);
|
||||
if (ccrev >= 21) {
|
||||
/* Turn off UART clock before switching clocksource. */
|
||||
bcma_cc_write32(cc, BCMA_CC_CORECTL,
|
||||
bcma_cc_read32(cc, BCMA_CC_CORECTL)
|
||||
& ~BCMA_CC_CORECTL_UARTCLKEN);
|
||||
}
|
||||
/* Set the override bit so we don't divide it */
|
||||
bcma_cc_write32(cc, BCMA_CC_CORECTL,
|
||||
bcma_cc_read32(cc, BCMA_CC_CORECTL)
|
||||
| BCMA_CC_CORECTL_UARTCLK0);
|
||||
if (ccrev >= 21) {
|
||||
/* Re-enable the UART clock. */
|
||||
bcma_cc_write32(cc, BCMA_CC_CORECTL,
|
||||
bcma_cc_read32(cc, BCMA_CC_CORECTL)
|
||||
| BCMA_CC_CORECTL_UARTCLKEN);
|
||||
}
|
||||
} else {
|
||||
pr_err("serial not supported on this device ccrev: 0x%x\n",
|
||||
ccrev);
|
||||
return;
|
||||
}
|
||||
|
||||
irq = bcma_core_mips_irq(cc->core);
|
||||
|
||||
/* Determine the registers of the UARTs */
|
||||
cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART);
|
||||
for (i = 0; i < cc->nr_serial_ports; i++) {
|
||||
ports[i].regs = cc->core->io_addr + BCMA_CC_UART0_DATA +
|
||||
(i * 256);
|
||||
ports[i].irq = irq;
|
||||
ports[i].baud_base = baud_base;
|
||||
ports[i].reg_shift = 0;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_BCMA_DRIVER_MIPS */
|
||||
|
|
|
@ -11,6 +11,13 @@
|
|||
#include "bcma_private.h"
|
||||
#include <linux/bcma/bcma.h>
|
||||
|
||||
static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
|
||||
{
|
||||
bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
|
||||
bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
|
||||
return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
|
||||
}
|
||||
|
||||
static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
|
||||
u32 offset, u32 mask, u32 set)
|
||||
{
|
||||
|
@ -136,3 +143,129 @@ void bcma_pmu_init(struct bcma_drv_cc *cc)
|
|||
bcma_pmu_swreg_init(cc);
|
||||
bcma_pmu_workarounds(cc);
|
||||
}
|
||||
|
||||
u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc)
|
||||
{
|
||||
struct bcma_bus *bus = cc->core->bus;
|
||||
|
||||
switch (bus->chipinfo.id) {
|
||||
case 0x4716:
|
||||
case 0x4748:
|
||||
case 47162:
|
||||
case 0x4313:
|
||||
case 0x5357:
|
||||
case 0x4749:
|
||||
case 53572:
|
||||
/* always 20Mhz */
|
||||
return 20000 * 1000;
|
||||
case 0x5356:
|
||||
case 0x5300:
|
||||
/* always 25Mhz */
|
||||
return 25000 * 1000;
|
||||
default:
|
||||
pr_warn("No ALP clock specified for %04X device, "
|
||||
"pmu rev. %d, using default %d Hz\n",
|
||||
bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK);
|
||||
}
|
||||
return BCMA_CC_PMU_ALP_CLOCK;
|
||||
}
|
||||
|
||||
/* Find the output of the "m" pll divider given pll controls that start with
|
||||
* pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc.
|
||||
*/
|
||||
static u32 bcma_pmu_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m)
|
||||
{
|
||||
u32 tmp, div, ndiv, p1, p2, fc;
|
||||
struct bcma_bus *bus = cc->core->bus;
|
||||
|
||||
BUG_ON((pll0 & 3) || (pll0 > BCMA_CC_PMU4716_MAINPLL_PLL0));
|
||||
|
||||
BUG_ON(!m || m > 4);
|
||||
|
||||
if (bus->chipinfo.id == 0x5357 || bus->chipinfo.id == 0x4749) {
|
||||
/* Detect failure in clock setting */
|
||||
tmp = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
|
||||
if (tmp & 0x40000)
|
||||
return 133 * 1000000;
|
||||
}
|
||||
|
||||
tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_P1P2_OFF);
|
||||
p1 = (tmp & BCMA_CC_PPL_P1_MASK) >> BCMA_CC_PPL_P1_SHIFT;
|
||||
p2 = (tmp & BCMA_CC_PPL_P2_MASK) >> BCMA_CC_PPL_P2_SHIFT;
|
||||
|
||||
tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_M14_OFF);
|
||||
div = (tmp >> ((m - 1) * BCMA_CC_PPL_MDIV_WIDTH)) &
|
||||
BCMA_CC_PPL_MDIV_MASK;
|
||||
|
||||
tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_NM5_OFF);
|
||||
ndiv = (tmp & BCMA_CC_PPL_NDIV_MASK) >> BCMA_CC_PPL_NDIV_SHIFT;
|
||||
|
||||
/* Do calculation in Mhz */
|
||||
fc = bcma_pmu_alp_clock(cc) / 1000000;
|
||||
fc = (p1 * ndiv * fc) / p2;
|
||||
|
||||
/* Return clock in Hertz */
|
||||
return (fc / div) * 1000000;
|
||||
}
|
||||
|
||||
/* query bus clock frequency for PMU-enabled chipcommon */
|
||||
u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
|
||||
{
|
||||
struct bcma_bus *bus = cc->core->bus;
|
||||
|
||||
switch (bus->chipinfo.id) {
|
||||
case 0x4716:
|
||||
case 0x4748:
|
||||
case 47162:
|
||||
return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0,
|
||||
BCMA_CC_PMU5_MAINPLL_SSB);
|
||||
case 0x5356:
|
||||
return bcma_pmu_clock(cc, BCMA_CC_PMU5356_MAINPLL_PLL0,
|
||||
BCMA_CC_PMU5_MAINPLL_SSB);
|
||||
case 0x5357:
|
||||
case 0x4749:
|
||||
return bcma_pmu_clock(cc, BCMA_CC_PMU5357_MAINPLL_PLL0,
|
||||
BCMA_CC_PMU5_MAINPLL_SSB);
|
||||
case 0x5300:
|
||||
return bcma_pmu_clock(cc, BCMA_CC_PMU4706_MAINPLL_PLL0,
|
||||
BCMA_CC_PMU5_MAINPLL_SSB);
|
||||
case 53572:
|
||||
return 75000000;
|
||||
default:
|
||||
pr_warn("No backplane clock specified for %04X device, "
|
||||
"pmu rev. %d, using default %d Hz\n",
|
||||
bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_HT_CLOCK);
|
||||
}
|
||||
return BCMA_CC_PMU_HT_CLOCK;
|
||||
}
|
||||
|
||||
/* query cpu clock frequency for PMU-enabled chipcommon */
|
||||
u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc)
|
||||
{
|
||||
struct bcma_bus *bus = cc->core->bus;
|
||||
|
||||
if (bus->chipinfo.id == 53572)
|
||||
return 300000000;
|
||||
|
||||
if (cc->pmu.rev >= 5) {
|
||||
u32 pll;
|
||||
switch (bus->chipinfo.id) {
|
||||
case 0x5356:
|
||||
pll = BCMA_CC_PMU5356_MAINPLL_PLL0;
|
||||
break;
|
||||
case 0x5357:
|
||||
case 0x4749:
|
||||
pll = BCMA_CC_PMU5357_MAINPLL_PLL0;
|
||||
break;
|
||||
default:
|
||||
pll = BCMA_CC_PMU4716_MAINPLL_PLL0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* TODO: if (bus->chipinfo.id == 0x5300)
|
||||
return si_4706_pmu_clock(sih, osh, cc, PMU4706_MAINPLL_PLL0, PMU5_MAINPLL_CPU); */
|
||||
return bcma_pmu_clock(cc, pll, BCMA_CC_PMU5_MAINPLL_CPU);
|
||||
}
|
||||
|
||||
return bcma_pmu_get_clockcontrol(cc);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
* Broadcom specific AMBA
|
||||
* Broadcom MIPS32 74K core driver
|
||||
*
|
||||
* Copyright 2009, Broadcom Corporation
|
||||
* Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
|
||||
* Copyright 2010, Bernhard Loos <bernhardloos@googlemail.com>
|
||||
* Copyright 2011, Hauke Mehrtens <hauke@hauke-m.de>
|
||||
*
|
||||
* Licensed under the GNU/GPL. See COPYING for details.
|
||||
*/
|
||||
|
||||
#include "bcma_private.h"
|
||||
|
||||
#include <linux/bcma/bcma.h>
|
||||
|
||||
#include <linux/serial.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/serial_reg.h>
|
||||
#include <linux/time.h>
|
||||
|
||||
/* The 47162a0 hangs when reading MIPS DMP registers registers */
|
||||
static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
|
||||
{
|
||||
return dev->bus->chipinfo.id == 47162 && dev->bus->chipinfo.rev == 0 &&
|
||||
dev->id.id == BCMA_CORE_MIPS_74K;
|
||||
}
|
||||
|
||||
/* The 5357b0 hangs when reading USB20H DMP registers */
|
||||
static inline bool bcma_core_mips_bcm5357b0_quirk(struct bcma_device *dev)
|
||||
{
|
||||
return (dev->bus->chipinfo.id == 0x5357 ||
|
||||
dev->bus->chipinfo.id == 0x4749) &&
|
||||
dev->bus->chipinfo.pkg == 11 &&
|
||||
dev->id.id == BCMA_CORE_USB20_HOST;
|
||||
}
|
||||
|
||||
static inline u32 mips_read32(struct bcma_drv_mips *mcore,
|
||||
u16 offset)
|
||||
{
|
||||
return bcma_read32(mcore->core, offset);
|
||||
}
|
||||
|
||||
static inline void mips_write32(struct bcma_drv_mips *mcore,
|
||||
u16 offset,
|
||||
u32 value)
|
||||
{
|
||||
bcma_write32(mcore->core, offset, value);
|
||||
}
|
||||
|
||||
static const u32 ipsflag_irq_mask[] = {
|
||||
0,
|
||||
BCMA_MIPS_IPSFLAG_IRQ1,
|
||||
BCMA_MIPS_IPSFLAG_IRQ2,
|
||||
BCMA_MIPS_IPSFLAG_IRQ3,
|
||||
BCMA_MIPS_IPSFLAG_IRQ4,
|
||||
};
|
||||
|
||||
static const u32 ipsflag_irq_shift[] = {
|
||||
0,
|
||||
BCMA_MIPS_IPSFLAG_IRQ1_SHIFT,
|
||||
BCMA_MIPS_IPSFLAG_IRQ2_SHIFT,
|
||||
BCMA_MIPS_IPSFLAG_IRQ3_SHIFT,
|
||||
BCMA_MIPS_IPSFLAG_IRQ4_SHIFT,
|
||||
};
|
||||
|
||||
static u32 bcma_core_mips_irqflag(struct bcma_device *dev)
|
||||
{
|
||||
u32 flag;
|
||||
|
||||
if (bcma_core_mips_bcm47162a0_quirk(dev))
|
||||
return dev->core_index;
|
||||
if (bcma_core_mips_bcm5357b0_quirk(dev))
|
||||
return dev->core_index;
|
||||
flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30);
|
||||
|
||||
return flag & 0x1F;
|
||||
}
|
||||
|
||||
/* Get the MIPS IRQ assignment for a specified device.
|
||||
* If unassigned, 0 is returned.
|
||||
*/
|
||||
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);
|
||||
|
||||
for (irq = 1; irq <= 4; irq++)
|
||||
if (bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq)) &
|
||||
(1 << irqflag))
|
||||
return irq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(bcma_core_mips_irq);
|
||||
|
||||
static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
|
||||
{
|
||||
unsigned int oldirq = bcma_core_mips_irq(dev);
|
||||
struct bcma_bus *bus = dev->bus;
|
||||
struct bcma_device *mdev = bus->drv_mips.core;
|
||||
u32 irqflag;
|
||||
|
||||
irqflag = bcma_core_mips_irqflag(dev);
|
||||
BUG_ON(oldirq == 6);
|
||||
|
||||
dev->irq = irq + 2;
|
||||
|
||||
/* clear the old irq */
|
||||
if (oldirq == 0)
|
||||
bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
|
||||
bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) &
|
||||
~(1 << irqflag));
|
||||
else
|
||||
bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq), 0);
|
||||
|
||||
/* assign the new one */
|
||||
if (irq == 0) {
|
||||
bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
|
||||
bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) |
|
||||
(1 << irqflag));
|
||||
} else {
|
||||
u32 oldirqflag = bcma_read32(mdev,
|
||||
BCMA_MIPS_MIPS74K_INTMASK(irq));
|
||||
if (oldirqflag) {
|
||||
struct bcma_device *core;
|
||||
|
||||
/* backplane irq line is in use, find out who uses
|
||||
* it and set user to irq 0
|
||||
*/
|
||||
list_for_each_entry_reverse(core, &bus->cores, list) {
|
||||
if ((1 << bcma_core_mips_irqflag(core)) ==
|
||||
oldirqflag) {
|
||||
bcma_core_mips_set_irq(core, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq),
|
||||
1 << irqflag);
|
||||
}
|
||||
|
||||
pr_info("set_irq: core 0x%04x, irq %d => %d\n",
|
||||
dev->id.id, oldirq + 2, irq + 2);
|
||||
}
|
||||
|
||||
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);
|
||||
for (i = 0; i <= 6; i++)
|
||||
printk(" %s%s", irq_name[i], i == irq ? "*" : " ");
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
static void bcma_core_mips_dump_irq(struct bcma_bus *bus)
|
||||
{
|
||||
struct bcma_device *core;
|
||||
|
||||
list_for_each_entry_reverse(core, &bus->cores, list) {
|
||||
bcma_core_mips_print_irq(core, bcma_core_mips_irq(core));
|
||||
}
|
||||
}
|
||||
|
||||
u32 bcma_cpu_clock(struct bcma_drv_mips *mcore)
|
||||
{
|
||||
struct bcma_bus *bus = mcore->core->bus;
|
||||
|
||||
if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU)
|
||||
return bcma_pmu_get_clockcpu(&bus->drv_cc);
|
||||
|
||||
pr_err("No PMU available, need this to get the cpu clock\n");
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(bcma_cpu_clock);
|
||||
|
||||
static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
|
||||
{
|
||||
struct bcma_bus *bus = mcore->core->bus;
|
||||
|
||||
switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
|
||||
case BCMA_CC_FLASHT_STSER:
|
||||
case BCMA_CC_FLASHT_ATSER:
|
||||
pr_err("Serial flash not supported.\n");
|
||||
break;
|
||||
case BCMA_CC_FLASHT_PARA:
|
||||
pr_info("found parallel flash.\n");
|
||||
bus->drv_cc.pflash.window = 0x1c000000;
|
||||
bus->drv_cc.pflash.window_size = 0x02000000;
|
||||
|
||||
if ((bcma_read32(bus->drv_cc.core, BCMA_CC_FLASH_CFG) &
|
||||
BCMA_CC_FLASH_CFG_DS) == 0)
|
||||
bus->drv_cc.pflash.buswidth = 1;
|
||||
else
|
||||
bus->drv_cc.pflash.buswidth = 2;
|
||||
break;
|
||||
default:
|
||||
pr_err("flash not supported.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void bcma_core_mips_init(struct bcma_drv_mips *mcore)
|
||||
{
|
||||
struct bcma_bus *bus;
|
||||
struct bcma_device *core;
|
||||
bus = mcore->core->bus;
|
||||
|
||||
pr_info("Initializing MIPS core...\n");
|
||||
|
||||
if (!mcore->setup_done)
|
||||
mcore->assigned_irqs = 1;
|
||||
|
||||
/* Assign IRQs to all cores on the bus */
|
||||
list_for_each_entry_reverse(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;
|
||||
}
|
||||
}
|
||||
pr_info("IRQ reconfiguration done\n");
|
||||
bcma_core_mips_dump_irq(bus);
|
||||
|
||||
if (mcore->setup_done)
|
||||
return;
|
||||
|
||||
bcma_chipco_serial_init(&bus->drv_cc);
|
||||
bcma_core_mips_flash_detect(mcore);
|
||||
mcore->setup_done = true;
|
||||
}
|
|
@ -173,7 +173,7 @@ static bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc)
|
|||
return false;
|
||||
|
||||
#ifdef CONFIG_SSB_DRIVER_PCICORE
|
||||
if (bus->sprom.boardflags_lo & SSB_PCICORE_BFL_NOPCI)
|
||||
if (bus->sprom.boardflags_lo & SSB_BFL_NOPCI)
|
||||
return false;
|
||||
#endif /* CONFIG_SSB_DRIVER_PCICORE */
|
||||
|
||||
|
@ -189,6 +189,9 @@ static bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc)
|
|||
|
||||
void bcma_core_pci_init(struct bcma_drv_pci *pc)
|
||||
{
|
||||
if (pc->setup_done)
|
||||
return;
|
||||
|
||||
if (bcma_core_pci_is_in_hostmode(pc)) {
|
||||
#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
|
||||
bcma_core_pci_hostmode_init(pc);
|
||||
|
@ -198,6 +201,8 @@ void bcma_core_pci_init(struct bcma_drv_pci *pc)
|
|||
} else {
|
||||
bcma_core_pci_clientmode_init(pc);
|
||||
}
|
||||
|
||||
pc->setup_done = true;
|
||||
}
|
||||
|
||||
int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
|
||||
|
@ -205,7 +210,14 @@ int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
|
|||
{
|
||||
struct pci_dev *pdev = pc->core->bus->host_pci;
|
||||
u32 coremask, tmp;
|
||||
int err;
|
||||
int err = 0;
|
||||
|
||||
if (core->bus->hosttype != BCMA_HOSTTYPE_PCI) {
|
||||
/* This bcma device is not on a PCI host-bus. So the IRQs are
|
||||
* not routed through the PCI core.
|
||||
* So we must not enable routing through the PCI core. */
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp);
|
||||
if (err)
|
||||
|
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* Broadcom specific AMBA
|
||||
* System on Chip (SoC) Host
|
||||
*
|
||||
* Licensed under the GNU/GPL. See COPYING for details.
|
||||
*/
|
||||
|
||||
#include "bcma_private.h"
|
||||
#include "scan.h"
|
||||
#include <linux/bcma/bcma.h>
|
||||
#include <linux/bcma/bcma_soc.h>
|
||||
|
||||
static u8 bcma_host_soc_read8(struct bcma_device *core, u16 offset)
|
||||
{
|
||||
return readb(core->io_addr + offset);
|
||||
}
|
||||
|
||||
static u16 bcma_host_soc_read16(struct bcma_device *core, u16 offset)
|
||||
{
|
||||
return readw(core->io_addr + offset);
|
||||
}
|
||||
|
||||
static u32 bcma_host_soc_read32(struct bcma_device *core, u16 offset)
|
||||
{
|
||||
return readl(core->io_addr + offset);
|
||||
}
|
||||
|
||||
static void bcma_host_soc_write8(struct bcma_device *core, u16 offset,
|
||||
u8 value)
|
||||
{
|
||||
writeb(value, core->io_addr + offset);
|
||||
}
|
||||
|
||||
static void bcma_host_soc_write16(struct bcma_device *core, u16 offset,
|
||||
u16 value)
|
||||
{
|
||||
writew(value, core->io_addr + offset);
|
||||
}
|
||||
|
||||
static void bcma_host_soc_write32(struct bcma_device *core, u16 offset,
|
||||
u32 value)
|
||||
{
|
||||
writel(value, core->io_addr + offset);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BCMA_BLOCKIO
|
||||
static void bcma_host_soc_block_read(struct bcma_device *core, void *buffer,
|
||||
size_t count, u16 offset, u8 reg_width)
|
||||
{
|
||||
void __iomem *addr = core->io_addr + offset;
|
||||
|
||||
switch (reg_width) {
|
||||
case sizeof(u8): {
|
||||
u8 *buf = buffer;
|
||||
|
||||
while (count) {
|
||||
*buf = __raw_readb(addr);
|
||||
buf++;
|
||||
count--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case sizeof(u16): {
|
||||
__le16 *buf = buffer;
|
||||
|
||||
WARN_ON(count & 1);
|
||||
while (count) {
|
||||
*buf = (__force __le16)__raw_readw(addr);
|
||||
buf++;
|
||||
count -= 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case sizeof(u32): {
|
||||
__le32 *buf = buffer;
|
||||
|
||||
WARN_ON(count & 3);
|
||||
while (count) {
|
||||
*buf = (__force __le32)__raw_readl(addr);
|
||||
buf++;
|
||||
count -= 4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
WARN_ON(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void bcma_host_soc_block_write(struct bcma_device *core,
|
||||
const void *buffer,
|
||||
size_t count, u16 offset, u8 reg_width)
|
||||
{
|
||||
void __iomem *addr = core->io_addr + offset;
|
||||
|
||||
switch (reg_width) {
|
||||
case sizeof(u8): {
|
||||
const u8 *buf = buffer;
|
||||
|
||||
while (count) {
|
||||
__raw_writeb(*buf, addr);
|
||||
buf++;
|
||||
count--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case sizeof(u16): {
|
||||
const __le16 *buf = buffer;
|
||||
|
||||
WARN_ON(count & 1);
|
||||
while (count) {
|
||||
__raw_writew((__force u16)(*buf), addr);
|
||||
buf++;
|
||||
count -= 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case sizeof(u32): {
|
||||
const __le32 *buf = buffer;
|
||||
|
||||
WARN_ON(count & 3);
|
||||
while (count) {
|
||||
__raw_writel((__force u32)(*buf), addr);
|
||||
buf++;
|
||||
count -= 4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
WARN_ON(1);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_BCMA_BLOCKIO */
|
||||
|
||||
static u32 bcma_host_soc_aread32(struct bcma_device *core, u16 offset)
|
||||
{
|
||||
return readl(core->io_wrap + offset);
|
||||
}
|
||||
|
||||
static void bcma_host_soc_awrite32(struct bcma_device *core, u16 offset,
|
||||
u32 value)
|
||||
{
|
||||
writel(value, core->io_wrap + offset);
|
||||
}
|
||||
|
||||
const struct bcma_host_ops bcma_host_soc_ops = {
|
||||
.read8 = bcma_host_soc_read8,
|
||||
.read16 = bcma_host_soc_read16,
|
||||
.read32 = bcma_host_soc_read32,
|
||||
.write8 = bcma_host_soc_write8,
|
||||
.write16 = bcma_host_soc_write16,
|
||||
.write32 = bcma_host_soc_write32,
|
||||
#ifdef CONFIG_BCMA_BLOCKIO
|
||||
.block_read = bcma_host_soc_block_read,
|
||||
.block_write = bcma_host_soc_block_write,
|
||||
#endif
|
||||
.aread32 = bcma_host_soc_aread32,
|
||||
.awrite32 = bcma_host_soc_awrite32,
|
||||
};
|
||||
|
||||
int __init bcma_host_soc_register(struct bcma_soc *soc)
|
||||
{
|
||||
struct bcma_bus *bus = &soc->bus;
|
||||
int err;
|
||||
|
||||
/* iomap only first core. We have to read some register on this core
|
||||
* to scan the bus.
|
||||
*/
|
||||
bus->mmio = ioremap_nocache(BCMA_ADDR_BASE, BCMA_CORE_SIZE * 1);
|
||||
if (!bus->mmio)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Host specific */
|
||||
bus->hosttype = BCMA_HOSTTYPE_SOC;
|
||||
bus->ops = &bcma_host_soc_ops;
|
||||
|
||||
/* Register */
|
||||
err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips);
|
||||
if (err)
|
||||
iounmap(bus->mmio);
|
||||
|
||||
return err;
|
||||
}
|
|
@ -66,6 +66,10 @@ static struct bcma_device *bcma_find_core(struct bcma_bus *bus, u16 coreid)
|
|||
static void bcma_release_core_dev(struct device *dev)
|
||||
{
|
||||
struct bcma_device *core = container_of(dev, struct bcma_device, dev);
|
||||
if (core->io_addr)
|
||||
iounmap(core->io_addr);
|
||||
if (core->io_wrap)
|
||||
iounmap(core->io_wrap);
|
||||
kfree(core);
|
||||
}
|
||||
|
||||
|
@ -80,6 +84,7 @@ static int bcma_register_cores(struct bcma_bus *bus)
|
|||
case BCMA_CORE_CHIPCOMMON:
|
||||
case BCMA_CORE_PCI:
|
||||
case BCMA_CORE_PCIE:
|
||||
case BCMA_CORE_MIPS_74K:
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -93,7 +98,10 @@ static int bcma_register_cores(struct bcma_bus *bus)
|
|||
core->dma_dev = &bus->host_pci->dev;
|
||||
core->irq = bus->host_pci->irq;
|
||||
break;
|
||||
case BCMA_HOSTTYPE_NONE:
|
||||
case BCMA_HOSTTYPE_SOC:
|
||||
core->dev.dma_mask = &core->dev.coherent_dma_mask;
|
||||
core->dma_dev = &core->dev;
|
||||
break;
|
||||
case BCMA_HOSTTYPE_SDIO:
|
||||
break;
|
||||
}
|
||||
|
@ -140,6 +148,13 @@ int bcma_bus_register(struct bcma_bus *bus)
|
|||
bcma_core_chipcommon_init(&bus->drv_cc);
|
||||
}
|
||||
|
||||
/* Init MIPS core */
|
||||
core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
|
||||
if (core) {
|
||||
bus->drv_mips.core = core;
|
||||
bcma_core_mips_init(&bus->drv_mips);
|
||||
}
|
||||
|
||||
/* Init PCIE core */
|
||||
core = bcma_find_core(bus, BCMA_CORE_PCIE);
|
||||
if (core) {
|
||||
|
@ -169,6 +184,59 @@ void bcma_bus_unregister(struct bcma_bus *bus)
|
|||
bcma_unregister_cores(bus);
|
||||
}
|
||||
|
||||
int __init bcma_bus_early_register(struct bcma_bus *bus,
|
||||
struct bcma_device *core_cc,
|
||||
struct bcma_device *core_mips)
|
||||
{
|
||||
int err;
|
||||
struct bcma_device *core;
|
||||
struct bcma_device_id match;
|
||||
|
||||
bcma_init_bus(bus);
|
||||
|
||||
match.manuf = BCMA_MANUF_BCM;
|
||||
match.id = BCMA_CORE_CHIPCOMMON;
|
||||
match.class = BCMA_CL_SIM;
|
||||
match.rev = BCMA_ANY_REV;
|
||||
|
||||
/* Scan for chip common core */
|
||||
err = bcma_bus_scan_early(bus, &match, core_cc);
|
||||
if (err) {
|
||||
pr_err("Failed to scan for common core: %d\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
match.manuf = BCMA_MANUF_MIPS;
|
||||
match.id = BCMA_CORE_MIPS_74K;
|
||||
match.class = BCMA_CL_SIM;
|
||||
match.rev = BCMA_ANY_REV;
|
||||
|
||||
/* Scan for mips core */
|
||||
err = bcma_bus_scan_early(bus, &match, core_mips);
|
||||
if (err) {
|
||||
pr_err("Failed to scan for mips core: %d\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Init CC core */
|
||||
core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
|
||||
if (core) {
|
||||
bus->drv_cc.core = core;
|
||||
bcma_core_chipcommon_init(&bus->drv_cc);
|
||||
}
|
||||
|
||||
/* Init MIPS core */
|
||||
core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
|
||||
if (core) {
|
||||
bus->drv_mips.core = core;
|
||||
bcma_core_mips_init(&bus->drv_mips);
|
||||
}
|
||||
|
||||
pr_info("Early bus registered\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __bcma_driver_register(struct bcma_driver *drv, struct module *owner)
|
||||
{
|
||||
drv->drv.name = drv->name;
|
||||
|
|
|
@ -200,56 +200,38 @@ static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 **eromptr,
|
|||
return addrl;
|
||||
}
|
||||
|
||||
int bcma_bus_scan(struct bcma_bus *bus)
|
||||
static struct bcma_device *bcma_find_core_by_index(struct bcma_bus *bus,
|
||||
u16 index)
|
||||
{
|
||||
u32 erombase;
|
||||
u32 __iomem *eromptr, *eromend;
|
||||
struct bcma_device *core;
|
||||
|
||||
list_for_each_entry(core, &bus->cores, list) {
|
||||
if (core->core_index == index)
|
||||
return core;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
|
||||
struct bcma_device_id *match, int core_num,
|
||||
struct bcma_device *core)
|
||||
{
|
||||
s32 tmp;
|
||||
u8 i, j;
|
||||
s32 cia, cib;
|
||||
u8 ports[2], wrappers[2];
|
||||
|
||||
s32 tmp;
|
||||
u8 i, j;
|
||||
|
||||
int err;
|
||||
|
||||
INIT_LIST_HEAD(&bus->cores);
|
||||
bus->nr_cores = 0;
|
||||
|
||||
bcma_scan_switch_core(bus, BCMA_ADDR_BASE);
|
||||
|
||||
tmp = bcma_scan_read32(bus, 0, BCMA_CC_ID);
|
||||
bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
|
||||
bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
|
||||
bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
|
||||
|
||||
erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
|
||||
eromptr = bus->mmio;
|
||||
eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
|
||||
|
||||
bcma_scan_switch_core(bus, erombase);
|
||||
|
||||
while (eromptr < eromend) {
|
||||
struct bcma_device *core = kzalloc(sizeof(*core), GFP_KERNEL);
|
||||
if (!core)
|
||||
return -ENOMEM;
|
||||
INIT_LIST_HEAD(&core->list);
|
||||
core->bus = bus;
|
||||
|
||||
/* get CIs */
|
||||
cia = bcma_erom_get_ci(bus, &eromptr);
|
||||
cia = bcma_erom_get_ci(bus, eromptr);
|
||||
if (cia < 0) {
|
||||
bcma_erom_push_ent(&eromptr);
|
||||
if (bcma_erom_is_end(bus, &eromptr))
|
||||
break;
|
||||
err= -EILSEQ;
|
||||
goto out;
|
||||
}
|
||||
cib = bcma_erom_get_ci(bus, &eromptr);
|
||||
if (cib < 0) {
|
||||
err= -EILSEQ;
|
||||
goto out;
|
||||
bcma_erom_push_ent(eromptr);
|
||||
if (bcma_erom_is_end(bus, eromptr))
|
||||
return -ESPIPE;
|
||||
return -EILSEQ;
|
||||
}
|
||||
cib = bcma_erom_get_ci(bus, eromptr);
|
||||
if (cib < 0)
|
||||
return -EILSEQ;
|
||||
|
||||
/* parse CIs */
|
||||
core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
|
||||
|
@ -264,8 +246,8 @@ int bcma_bus_scan(struct bcma_bus *bus)
|
|||
if (((core->id.manuf == BCMA_MANUF_ARM) &&
|
||||
(core->id.id == 0xFFF)) ||
|
||||
(ports[1] == 0)) {
|
||||
bcma_erom_skip_component(bus, &eromptr);
|
||||
continue;
|
||||
bcma_erom_skip_component(bus, eromptr);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
/* check if component is a core at all */
|
||||
|
@ -273,28 +255,41 @@ int bcma_bus_scan(struct bcma_bus *bus)
|
|||
/* we could save addrl of the router
|
||||
if (cid == BCMA_CORE_OOB_ROUTER)
|
||||
*/
|
||||
bcma_erom_skip_component(bus, &eromptr);
|
||||
continue;
|
||||
bcma_erom_skip_component(bus, eromptr);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
if (bcma_erom_is_bridge(bus, &eromptr)) {
|
||||
bcma_erom_skip_component(bus, &eromptr);
|
||||
continue;
|
||||
if (bcma_erom_is_bridge(bus, eromptr)) {
|
||||
bcma_erom_skip_component(bus, eromptr);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
if (bcma_find_core_by_index(bus, core_num)) {
|
||||
bcma_erom_skip_component(bus, eromptr);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (match && ((match->manuf != BCMA_ANY_MANUF &&
|
||||
match->manuf != core->id.manuf) ||
|
||||
(match->id != BCMA_ANY_ID && match->id != core->id.id) ||
|
||||
(match->rev != BCMA_ANY_REV && match->rev != core->id.rev) ||
|
||||
(match->class != BCMA_ANY_CLASS && match->class != core->id.class)
|
||||
)) {
|
||||
bcma_erom_skip_component(bus, eromptr);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* get & parse master ports */
|
||||
for (i = 0; i < ports[0]; i++) {
|
||||
u32 mst_port_d = bcma_erom_get_mst_port(bus, &eromptr);
|
||||
if (mst_port_d < 0) {
|
||||
err= -EILSEQ;
|
||||
goto out;
|
||||
}
|
||||
u32 mst_port_d = bcma_erom_get_mst_port(bus, eromptr);
|
||||
if (mst_port_d < 0)
|
||||
return -EILSEQ;
|
||||
}
|
||||
|
||||
/* get & parse slave ports */
|
||||
for (i = 0; i < ports[1]; i++) {
|
||||
for (j = 0; ; j++) {
|
||||
tmp = bcma_erom_get_addr_desc(bus, &eromptr,
|
||||
tmp = bcma_erom_get_addr_desc(bus, eromptr,
|
||||
SCAN_ADDR_TYPE_SLAVE, i);
|
||||
if (tmp < 0) {
|
||||
/* no more entries for port _i_ */
|
||||
|
@ -311,7 +306,7 @@ int bcma_bus_scan(struct bcma_bus *bus)
|
|||
/* get & parse master wrappers */
|
||||
for (i = 0; i < wrappers[0]; i++) {
|
||||
for (j = 0; ; j++) {
|
||||
tmp = bcma_erom_get_addr_desc(bus, &eromptr,
|
||||
tmp = bcma_erom_get_addr_desc(bus, eromptr,
|
||||
SCAN_ADDR_TYPE_MWRAP, i);
|
||||
if (tmp < 0) {
|
||||
/* no more entries for port _i_ */
|
||||
|
@ -329,7 +324,7 @@ int bcma_bus_scan(struct bcma_bus *bus)
|
|||
for (i = 0; i < wrappers[1]; i++) {
|
||||
u8 hack = (ports[1] == 1) ? 0 : 1;
|
||||
for (j = 0; ; j++) {
|
||||
tmp = bcma_erom_get_addr_desc(bus, &eromptr,
|
||||
tmp = bcma_erom_get_addr_desc(bus, eromptr,
|
||||
SCAN_ADDR_TYPE_SWRAP, i + hack);
|
||||
if (tmp < 0) {
|
||||
/* no more entries for port _i_ */
|
||||
|
@ -342,19 +337,150 @@ int bcma_bus_scan(struct bcma_bus *bus)
|
|||
}
|
||||
}
|
||||
}
|
||||
if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
|
||||
core->io_addr = ioremap_nocache(core->addr, BCMA_CORE_SIZE);
|
||||
if (!core->io_addr)
|
||||
return -ENOMEM;
|
||||
core->io_wrap = ioremap_nocache(core->wrap, BCMA_CORE_SIZE);
|
||||
if (!core->io_wrap) {
|
||||
iounmap(core->io_addr);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bcma_init_bus(struct bcma_bus *bus)
|
||||
{
|
||||
s32 tmp;
|
||||
|
||||
if (bus->init_done)
|
||||
return;
|
||||
|
||||
INIT_LIST_HEAD(&bus->cores);
|
||||
bus->nr_cores = 0;
|
||||
|
||||
bcma_scan_switch_core(bus, BCMA_ADDR_BASE);
|
||||
|
||||
tmp = bcma_scan_read32(bus, 0, BCMA_CC_ID);
|
||||
bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
|
||||
bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
|
||||
bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
|
||||
bus->init_done = true;
|
||||
}
|
||||
|
||||
int bcma_bus_scan(struct bcma_bus *bus)
|
||||
{
|
||||
u32 erombase;
|
||||
u32 __iomem *eromptr, *eromend;
|
||||
|
||||
int err, core_num = 0;
|
||||
|
||||
bcma_init_bus(bus);
|
||||
|
||||
erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
|
||||
if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
|
||||
eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
|
||||
if (!eromptr)
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
eromptr = bus->mmio;
|
||||
}
|
||||
|
||||
eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
|
||||
|
||||
bcma_scan_switch_core(bus, erombase);
|
||||
|
||||
while (eromptr < eromend) {
|
||||
struct bcma_device *core = kzalloc(sizeof(*core), GFP_KERNEL);
|
||||
if (!core)
|
||||
return -ENOMEM;
|
||||
INIT_LIST_HEAD(&core->list);
|
||||
core->bus = bus;
|
||||
|
||||
err = bcma_get_next_core(bus, &eromptr, NULL, core_num, core);
|
||||
if (err == -ENODEV) {
|
||||
core_num++;
|
||||
continue;
|
||||
} else if (err == -ENXIO)
|
||||
continue;
|
||||
else if (err == -ESPIPE)
|
||||
break;
|
||||
else if (err < 0)
|
||||
return err;
|
||||
|
||||
core->core_index = core_num++;
|
||||
bus->nr_cores++;
|
||||
|
||||
pr_info("Core %d found: %s "
|
||||
"(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
|
||||
bus->nr_cores, bcma_device_name(&core->id),
|
||||
core->core_index, bcma_device_name(&core->id),
|
||||
core->id.manuf, core->id.id, core->id.rev,
|
||||
core->id.class);
|
||||
|
||||
core->core_index = bus->nr_cores++;
|
||||
list_add(&core->list, &bus->cores);
|
||||
continue;
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
if (bus->hosttype == BCMA_HOSTTYPE_SOC)
|
||||
iounmap(eromptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init bcma_bus_scan_early(struct bcma_bus *bus,
|
||||
struct bcma_device_id *match,
|
||||
struct bcma_device *core)
|
||||
{
|
||||
u32 erombase;
|
||||
u32 __iomem *eromptr, *eromend;
|
||||
|
||||
int err = -ENODEV;
|
||||
int core_num = 0;
|
||||
|
||||
erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
|
||||
if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
|
||||
eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
|
||||
if (!eromptr)
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
eromptr = bus->mmio;
|
||||
}
|
||||
|
||||
eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
|
||||
|
||||
bcma_scan_switch_core(bus, erombase);
|
||||
|
||||
while (eromptr < eromend) {
|
||||
memset(core, 0, sizeof(*core));
|
||||
INIT_LIST_HEAD(&core->list);
|
||||
core->bus = bus;
|
||||
|
||||
err = bcma_get_next_core(bus, &eromptr, match, core_num, core);
|
||||
if (err == -ENODEV) {
|
||||
core_num++;
|
||||
continue;
|
||||
} else if (err == -ENXIO)
|
||||
continue;
|
||||
else if (err == -ESPIPE)
|
||||
break;
|
||||
else if (err < 0)
|
||||
return err;
|
||||
|
||||
core->core_index = core_num++;
|
||||
bus->nr_cores++;
|
||||
pr_info("Core %d found: %s "
|
||||
"(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
|
||||
core->core_index, bcma_device_name(&core->id),
|
||||
core->id.manuf, core->id.id, core->id.rev,
|
||||
core->id.class);
|
||||
|
||||
list_add(&core->list, &bus->cores);
|
||||
err = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (bus->hosttype == BCMA_HOSTTYPE_SOC)
|
||||
iounmap(eromptr);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -25,5 +25,6 @@ config ATH_DEBUG
|
|||
source "drivers/net/wireless/ath/ath5k/Kconfig"
|
||||
source "drivers/net/wireless/ath/ath9k/Kconfig"
|
||||
source "drivers/net/wireless/ath/carl9170/Kconfig"
|
||||
source "drivers/net/wireless/ath/ath6kl/Kconfig"
|
||||
|
||||
endif
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
obj-$(CONFIG_ATH5K) += ath5k/
|
||||
obj-$(CONFIG_ATH9K_HW) += ath9k/
|
||||
obj-$(CONFIG_CARL9170) += carl9170/
|
||||
obj-$(CONFIG_ATH6KL) += ath6kl/
|
||||
|
||||
obj-$(CONFIG_ATH_COMMON) += ath.o
|
||||
|
||||
|
|
|
@ -169,7 +169,7 @@ static int ath_ahb_probe(struct platform_device *pdev)
|
|||
__set_bit(ATH_STAT_2G_DISABLED, ah->status);
|
||||
}
|
||||
|
||||
ret = ath5k_init_softc(ah, &ath_ahb_bus_ops);
|
||||
ret = ath5k_init_ah(ah, &ath_ahb_bus_ops);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "failed to attach device, err=%d\n", ret);
|
||||
ret = -ENODEV;
|
||||
|
@ -214,7 +214,7 @@ static int ath_ahb_remove(struct platform_device *pdev)
|
|||
__raw_writel(reg, (void __iomem *) AR5K_AR5312_ENABLE);
|
||||
}
|
||||
|
||||
ath5k_deinit_softc(ah);
|
||||
ath5k_deinit_ah(ah);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
ieee80211_free_hw(hw);
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
*/
|
||||
|
||||
#include "ath5k.h"
|
||||
#include "base.h"
|
||||
#include "reg.h"
|
||||
#include "debug.h"
|
||||
#include "ani.h"
|
||||
|
|
|
@ -16,6 +16,10 @@
|
|||
#ifndef ANI_H
|
||||
#define ANI_H
|
||||
|
||||
#include "../ath.h"
|
||||
|
||||
enum ath5k_phy_error_code;
|
||||
|
||||
/* these thresholds are relative to the ATH5K_ANI_LISTEN_PERIOD */
|
||||
#define ATH5K_ANI_LISTEN_PERIOD 100
|
||||
#define ATH5K_ANI_OFDM_TRIG_HIGH 500
|
||||
|
|
|
@ -131,13 +131,6 @@
|
|||
#define AR5K_REG_DISABLE_BITS(ah, _reg, _flags) \
|
||||
ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) & ~(_flags), _reg)
|
||||
|
||||
/* Access to PHY registers */
|
||||
#define AR5K_PHY_READ(ah, _reg) \
|
||||
ath5k_hw_reg_read(ah, (ah)->ah_phy + ((_reg) << 2))
|
||||
|
||||
#define AR5K_PHY_WRITE(ah, _reg, _val) \
|
||||
ath5k_hw_reg_write(ah, _val, (ah)->ah_phy + ((_reg) << 2))
|
||||
|
||||
/* Access QCU registers per queue */
|
||||
#define AR5K_REG_READ_Q(ah, _reg, _queue) \
|
||||
(ath5k_hw_reg_read(ah, _reg) & (1 << _queue)) \
|
||||
|
@ -166,7 +159,6 @@
|
|||
#define AR5K_TUNE_DMA_BEACON_RESP 2
|
||||
#define AR5K_TUNE_SW_BEACON_RESP 10
|
||||
#define AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF 0
|
||||
#define AR5K_TUNE_RADAR_ALERT false
|
||||
#define AR5K_TUNE_MIN_TX_FIFO_THRES 1
|
||||
#define AR5K_TUNE_MAX_TX_FIFO_THRES ((IEEE80211_MAX_FRAME_LEN / 64) + 1)
|
||||
#define AR5K_TUNE_REGISTER_TIMEOUT 20000
|
||||
|
@ -295,17 +287,6 @@ enum ath5k_radio {
|
|||
* Common silicon revision/version values
|
||||
*/
|
||||
|
||||
enum ath5k_srev_type {
|
||||
AR5K_VERSION_MAC,
|
||||
AR5K_VERSION_RAD,
|
||||
};
|
||||
|
||||
struct ath5k_srev_name {
|
||||
const char *sr_name;
|
||||
enum ath5k_srev_type sr_type;
|
||||
u_int sr_val;
|
||||
};
|
||||
|
||||
#define AR5K_SREV_UNKNOWN 0xffff
|
||||
|
||||
#define AR5K_SREV_AR5210 0x00 /* Crete */
|
||||
|
@ -424,7 +405,6 @@ enum ath5k_driver_mode {
|
|||
AR5K_MODE_11A = 0,
|
||||
AR5K_MODE_11B = 1,
|
||||
AR5K_MODE_11G = 2,
|
||||
AR5K_MODE_XR = 0,
|
||||
AR5K_MODE_MAX = 3
|
||||
};
|
||||
|
||||
|
@ -694,33 +674,6 @@ struct ath5k_gain {
|
|||
#define AR5K_SLOT_TIME_20 880
|
||||
#define AR5K_SLOT_TIME_MAX 0xffff
|
||||
|
||||
/* channel_flags */
|
||||
#define CHANNEL_CW_INT 0x0008 /* Contention Window interference detected */
|
||||
#define CHANNEL_CCK 0x0020 /* CCK channel */
|
||||
#define CHANNEL_OFDM 0x0040 /* OFDM channel */
|
||||
#define CHANNEL_2GHZ 0x0080 /* 2GHz channel. */
|
||||
#define CHANNEL_5GHZ 0x0100 /* 5GHz channel */
|
||||
#define CHANNEL_PASSIVE 0x0200 /* Only passive scan allowed */
|
||||
#define CHANNEL_DYN 0x0400 /* Dynamic CCK-OFDM channel (for g operation) */
|
||||
#define CHANNEL_XR 0x0800 /* XR channel */
|
||||
|
||||
#define CHANNEL_A (CHANNEL_5GHZ | CHANNEL_OFDM)
|
||||
#define CHANNEL_B (CHANNEL_2GHZ | CHANNEL_CCK)
|
||||
#define CHANNEL_G (CHANNEL_2GHZ | CHANNEL_OFDM)
|
||||
#define CHANNEL_X (CHANNEL_5GHZ | CHANNEL_OFDM | CHANNEL_XR)
|
||||
|
||||
#define CHANNEL_ALL (CHANNEL_OFDM | CHANNEL_CCK | \
|
||||
CHANNEL_2GHZ | CHANNEL_5GHZ)
|
||||
|
||||
#define CHANNEL_MODES CHANNEL_ALL
|
||||
|
||||
/*
|
||||
* Used internally for ath5k_hw_reset_tx_queue().
|
||||
* Also see struct struct ieee80211_channel.
|
||||
*/
|
||||
#define IS_CHAN_XR(_c) ((_c->hw_value & CHANNEL_XR) != 0)
|
||||
#define IS_CHAN_B(_c) ((_c->hw_value & CHANNEL_B) != 0)
|
||||
|
||||
/*
|
||||
* The following structure is used to map 2GHz channels to
|
||||
* 5GHz Atheros channels.
|
||||
|
@ -977,7 +930,7 @@ enum ath5k_power_mode {
|
|||
struct ath5k_capabilities {
|
||||
/*
|
||||
* Supported PHY modes
|
||||
* (ie. CHANNEL_A, CHANNEL_B, ...)
|
||||
* (ie. AR5K_MODE_11A, AR5K_MODE_11B, ...)
|
||||
*/
|
||||
DECLARE_BITMAP(cap_mode, AR5K_MODE_MAX);
|
||||
|
||||
|
@ -1013,16 +966,6 @@ struct ath5k_nfcal_hist {
|
|||
s16 nfval[ATH5K_NF_CAL_HIST_MAX]; /* last few noise floors */
|
||||
};
|
||||
|
||||
/**
|
||||
* struct avg_val - Helper structure for average calculation
|
||||
* @avg: contains the actual average value
|
||||
* @avg_weight: is used internally during calculation to prevent rounding errors
|
||||
*/
|
||||
struct ath5k_avg_val {
|
||||
int avg;
|
||||
int avg_weight;
|
||||
};
|
||||
|
||||
#define ATH5K_LED_MAX_NAME_LEN 31
|
||||
|
||||
/*
|
||||
|
@ -1148,7 +1091,6 @@ struct ath5k_hw {
|
|||
bool rx_pending; /* rx tasklet pending */
|
||||
bool tx_pending; /* tx tasklet pending */
|
||||
|
||||
u8 lladdr[ETH_ALEN];
|
||||
u8 bssidmask[ETH_ALEN];
|
||||
|
||||
unsigned int led_pin, /* GPIO pin for driving LED */
|
||||
|
@ -1156,7 +1098,6 @@ struct ath5k_hw {
|
|||
|
||||
struct work_struct reset_work; /* deferred chip reset */
|
||||
|
||||
unsigned int rxbufsize; /* rx size based on mtu */
|
||||
struct list_head rxbuf; /* receive buffer */
|
||||
spinlock_t rxbuflock;
|
||||
u32 *rxlink; /* link ptr in last RX desc */
|
||||
|
@ -1208,10 +1149,8 @@ struct ath5k_hw {
|
|||
|
||||
enum ath5k_version ah_version;
|
||||
enum ath5k_radio ah_radio;
|
||||
u32 ah_phy;
|
||||
u32 ah_mac_srev;
|
||||
u16 ah_mac_version;
|
||||
u16 ah_mac_revision;
|
||||
u16 ah_phy_revision;
|
||||
u16 ah_radio_5ghz_revision;
|
||||
u16 ah_radio_2ghz_revision;
|
||||
|
@ -1279,12 +1218,6 @@ struct ath5k_hw {
|
|||
bool txp_setup;
|
||||
} ah_txpower;
|
||||
|
||||
struct {
|
||||
bool r_enabled;
|
||||
int r_last_alert;
|
||||
struct ieee80211_channel r_last_channel;
|
||||
} ah_radar;
|
||||
|
||||
struct ath5k_nfcal_hist ah_nfcal_hist;
|
||||
|
||||
/* average beacon RSSI in our BSS (used by ANI) */
|
||||
|
@ -1327,36 +1260,13 @@ struct ath_bus_ops {
|
|||
extern const struct ieee80211_ops ath5k_hw_ops;
|
||||
|
||||
/* Initialization and detach functions */
|
||||
int ath5k_init_softc(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops);
|
||||
void ath5k_deinit_softc(struct ath5k_hw *ah);
|
||||
int ath5k_hw_init(struct ath5k_hw *ah);
|
||||
void ath5k_hw_deinit(struct ath5k_hw *ah);
|
||||
|
||||
int ath5k_sysfs_register(struct ath5k_hw *ah);
|
||||
void ath5k_sysfs_unregister(struct ath5k_hw *ah);
|
||||
|
||||
/* base.c */
|
||||
struct ath5k_buf;
|
||||
struct ath5k_txq;
|
||||
|
||||
void ath5k_set_beacon_filter(struct ieee80211_hw *hw, bool enable);
|
||||
bool ath5k_any_vif_assoc(struct ath5k_hw *ah);
|
||||
void ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
|
||||
struct ath5k_txq *txq);
|
||||
int ath5k_start(struct ieee80211_hw *hw);
|
||||
void ath5k_stop(struct ieee80211_hw *hw);
|
||||
void ath5k_mode_setup(struct ath5k_hw *ah, struct ieee80211_vif *vif);
|
||||
void ath5k_update_bssid_mask_and_opmode(struct ath5k_hw *ah,
|
||||
struct ieee80211_vif *vif);
|
||||
int ath5k_chan_set(struct ath5k_hw *ah, struct ieee80211_channel *chan);
|
||||
void ath5k_beacon_update_timers(struct ath5k_hw *ah, u64 bc_tsf);
|
||||
int ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
|
||||
void ath5k_beacon_config(struct ath5k_hw *ah);
|
||||
void ath5k_txbuf_free_skb(struct ath5k_hw *ah, struct ath5k_buf *bf);
|
||||
void ath5k_rxbuf_free_skb(struct ath5k_hw *ah, struct ath5k_buf *bf);
|
||||
|
||||
/*Chip id helper functions */
|
||||
const char *ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val);
|
||||
int ath5k_hw_read_srev(struct ath5k_hw *ah);
|
||||
|
||||
/* LED functions */
|
||||
|
@ -1367,7 +1277,7 @@ void ath5k_unregister_leds(struct ath5k_hw *ah);
|
|||
|
||||
|
||||
/* Reset Functions */
|
||||
int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial);
|
||||
int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel);
|
||||
int ath5k_hw_on_hold(struct ath5k_hw *ah);
|
||||
int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
|
||||
struct ieee80211_channel *channel, bool fast, bool skip_pcu);
|
||||
|
@ -1487,13 +1397,13 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel);
|
|||
|
||||
/* PHY functions */
|
||||
/* Misc PHY functions */
|
||||
u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan);
|
||||
u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, enum ieee80211_band band);
|
||||
int ath5k_hw_phy_disable(struct ath5k_hw *ah);
|
||||
/* Gain_F optimization */
|
||||
enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah);
|
||||
int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah);
|
||||
/* PHY/RF channel functions */
|
||||
bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags);
|
||||
bool ath5k_channel_ok(struct ath5k_hw *ah, struct ieee80211_channel *channel);
|
||||
/* PHY calibration */
|
||||
void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah);
|
||||
int ath5k_hw_phy_calibrate(struct ath5k_hw *ah,
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include "ath5k.h"
|
||||
#include "reg.h"
|
||||
#include "debug.h"
|
||||
#include "base.h"
|
||||
|
||||
/**
|
||||
* ath5k_hw_post - Power On Self Test helper function
|
||||
|
@ -95,7 +94,7 @@ static int ath5k_hw_post(struct ath5k_hw *ah)
|
|||
/**
|
||||
* ath5k_hw_init - Check if hw is supported and init the needed structs
|
||||
*
|
||||
* @ah: The &struct ath5k_hw we got from the driver's init_softc function
|
||||
* @ah: The &struct ath5k_hw associated with the device
|
||||
*
|
||||
* Check if the device is supported, perform a POST and initialize the needed
|
||||
* structs. Returns -ENOMEM if we don't have memory for the needed structs,
|
||||
|
@ -114,7 +113,6 @@ int ath5k_hw_init(struct ath5k_hw *ah)
|
|||
/*
|
||||
* HW information
|
||||
*/
|
||||
ah->ah_radar.r_enabled = AR5K_TUNE_RADAR_ALERT;
|
||||
ah->ah_bwmode = AR5K_BWMODE_DEFAULT;
|
||||
ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
|
||||
ah->ah_imr = 0;
|
||||
|
@ -137,9 +135,8 @@ int ath5k_hw_init(struct ath5k_hw *ah)
|
|||
else
|
||||
ah->ah_version = AR5K_AR5212;
|
||||
|
||||
/* Get the MAC revision */
|
||||
/* Get the MAC version */
|
||||
ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER);
|
||||
ah->ah_mac_revision = AR5K_REG_MS(srev, AR5K_SREV_REV);
|
||||
|
||||
/* Fill the ath5k_hw struct with the needed functions */
|
||||
ret = ath5k_hw_init_desc_functions(ah);
|
||||
|
@ -147,7 +144,7 @@ int ath5k_hw_init(struct ath5k_hw *ah)
|
|||
goto err;
|
||||
|
||||
/* Bring device out of sleep and reset its units */
|
||||
ret = ath5k_hw_nic_wakeup(ah, 0, true);
|
||||
ret = ath5k_hw_nic_wakeup(ah, NULL);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
|
@ -155,8 +152,7 @@ int ath5k_hw_init(struct ath5k_hw *ah)
|
|||
ah->ah_phy_revision = ath5k_hw_reg_read(ah, AR5K_PHY_CHIP_ID) &
|
||||
0xffffffff;
|
||||
ah->ah_radio_5ghz_revision = ath5k_hw_radio_revision(ah,
|
||||
CHANNEL_5GHZ);
|
||||
ah->ah_phy = AR5K_PHY(0);
|
||||
IEEE80211_BAND_5GHZ);
|
||||
|
||||
/* Try to identify radio chip based on its srev */
|
||||
switch (ah->ah_radio_5ghz_revision & 0xf0) {
|
||||
|
@ -164,14 +160,14 @@ int ath5k_hw_init(struct ath5k_hw *ah)
|
|||
ah->ah_radio = AR5K_RF5111;
|
||||
ah->ah_single_chip = false;
|
||||
ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
|
||||
CHANNEL_2GHZ);
|
||||
IEEE80211_BAND_2GHZ);
|
||||
break;
|
||||
case AR5K_SREV_RAD_5112:
|
||||
case AR5K_SREV_RAD_2112:
|
||||
ah->ah_radio = AR5K_RF5112;
|
||||
ah->ah_single_chip = false;
|
||||
ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
|
||||
CHANNEL_2GHZ);
|
||||
IEEE80211_BAND_2GHZ);
|
||||
break;
|
||||
case AR5K_SREV_RAD_2413:
|
||||
ah->ah_radio = AR5K_RF2413;
|
||||
|
@ -208,7 +204,7 @@ int ath5k_hw_init(struct ath5k_hw *ah)
|
|||
ah->ah_radio = AR5K_RF5111;
|
||||
ah->ah_single_chip = false;
|
||||
ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
|
||||
CHANNEL_2GHZ);
|
||||
IEEE80211_BAND_2GHZ);
|
||||
} else if (ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4) ||
|
||||
ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4) ||
|
||||
ah->ah_phy_revision == AR5K_SREV_PHY_2425) {
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
#include <linux/uaccess.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/nl80211.h>
|
||||
|
||||
#include <net/ieee80211_radiotap.h>
|
||||
|
||||
|
@ -61,6 +62,8 @@
|
|||
#include "reg.h"
|
||||
#include "debug.h"
|
||||
#include "ani.h"
|
||||
#include "ath5k.h"
|
||||
#include "../regd.h"
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include "trace.h"
|
||||
|
@ -272,20 +275,18 @@ static unsigned int
|
|||
ath5k_setup_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels,
|
||||
unsigned int mode, unsigned int max)
|
||||
{
|
||||
unsigned int count, size, chfreq, freq, ch;
|
||||
unsigned int count, size, freq, ch;
|
||||
enum ieee80211_band band;
|
||||
|
||||
switch (mode) {
|
||||
case AR5K_MODE_11A:
|
||||
/* 1..220, but 2GHz frequencies are filtered by check_channel */
|
||||
size = 220;
|
||||
chfreq = CHANNEL_5GHZ;
|
||||
band = IEEE80211_BAND_5GHZ;
|
||||
break;
|
||||
case AR5K_MODE_11B:
|
||||
case AR5K_MODE_11G:
|
||||
size = 26;
|
||||
chfreq = CHANNEL_2GHZ;
|
||||
band = IEEE80211_BAND_2GHZ;
|
||||
break;
|
||||
default:
|
||||
|
@ -300,26 +301,19 @@ ath5k_setup_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels,
|
|||
if (freq == 0) /* mapping failed - not a standard channel */
|
||||
continue;
|
||||
|
||||
/* Write channel info, needed for ath5k_channel_ok() */
|
||||
channels[count].center_freq = freq;
|
||||
channels[count].band = band;
|
||||
channels[count].hw_value = mode;
|
||||
|
||||
/* Check if channel is supported by the chipset */
|
||||
if (!ath5k_channel_ok(ah, freq, chfreq))
|
||||
if (!ath5k_channel_ok(ah, &channels[count]))
|
||||
continue;
|
||||
|
||||
if (!modparam_all_channels &&
|
||||
!ath5k_is_standard_channel(ch, band))
|
||||
continue;
|
||||
|
||||
/* Write channel info and increment counter */
|
||||
channels[count].center_freq = freq;
|
||||
channels[count].band = band;
|
||||
switch (mode) {
|
||||
case AR5K_MODE_11A:
|
||||
case AR5K_MODE_11G:
|
||||
channels[count].hw_value = chfreq | CHANNEL_OFDM;
|
||||
break;
|
||||
case AR5K_MODE_11B:
|
||||
channels[count].hw_value = CHANNEL_B;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
|
@ -2349,7 +2343,7 @@ ath5k_tx_complete_poll_work(struct work_struct *work)
|
|||
\*************************/
|
||||
|
||||
int __devinit
|
||||
ath5k_init_softc(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops)
|
||||
ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops)
|
||||
{
|
||||
struct ieee80211_hw *hw = ah->hw;
|
||||
struct ath_common *common;
|
||||
|
@ -2867,7 +2861,6 @@ ath5k_init(struct ieee80211_hw *hw)
|
|||
}
|
||||
|
||||
SET_IEEE80211_PERM_ADDR(hw, mac);
|
||||
memcpy(&ah->lladdr, mac, ETH_ALEN);
|
||||
/* All MAC address bits matter for ACKs */
|
||||
ath5k_update_bssid_mask_and_opmode(ah, NULL);
|
||||
|
||||
|
@ -2903,7 +2896,7 @@ err:
|
|||
}
|
||||
|
||||
void
|
||||
ath5k_deinit_softc(struct ath5k_hw *ah)
|
||||
ath5k_deinit_ah(struct ath5k_hw *ah)
|
||||
{
|
||||
struct ieee80211_hw *hw = ah->hw;
|
||||
|
||||
|
|
|
@ -38,19 +38,27 @@
|
|||
/*
|
||||
* Definitions for the Atheros Wireless LAN controller driver.
|
||||
*/
|
||||
#ifndef _DEV_ATH_ATHVAR_H
|
||||
#define _DEV_ATH_ATHVAR_H
|
||||
#ifndef _DEV_ATH5K_BASE_H
|
||||
#define _DEV_ATH5K_BASE_H
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/rfkill.h>
|
||||
#include <linux/workqueue.h>
|
||||
struct ieee80211_vif;
|
||||
struct ieee80211_hw;
|
||||
struct ath5k_hw;
|
||||
struct ath5k_txq;
|
||||
struct ieee80211_channel;
|
||||
struct ath_bus_ops;
|
||||
enum nl80211_iftype;
|
||||
|
||||
#include "ath5k.h"
|
||||
#include "../regd.h"
|
||||
#include "../ath.h"
|
||||
enum ath5k_srev_type {
|
||||
AR5K_VERSION_MAC,
|
||||
AR5K_VERSION_RAD,
|
||||
};
|
||||
|
||||
struct ath5k_srev_name {
|
||||
const char *sr_name;
|
||||
enum ath5k_srev_type sr_type;
|
||||
u_int sr_val;
|
||||
};
|
||||
|
||||
struct ath5k_buf {
|
||||
struct list_head list;
|
||||
|
@ -65,7 +73,6 @@ struct ath5k_vif {
|
|||
enum nl80211_iftype opmode;
|
||||
int bslot;
|
||||
struct ath5k_buf *bbuf; /* beacon buffer */
|
||||
u8 lladdr[ETH_ALEN];
|
||||
};
|
||||
|
||||
struct ath5k_vif_iter_data {
|
||||
|
@ -78,8 +85,30 @@ struct ath5k_vif_iter_data {
|
|||
enum nl80211_iftype opmode;
|
||||
int n_stas;
|
||||
};
|
||||
void ath5k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif);
|
||||
|
||||
void ath5k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif);
|
||||
bool ath5k_any_vif_assoc(struct ath5k_hw *ah);
|
||||
|
||||
int ath5k_start(struct ieee80211_hw *hw);
|
||||
void ath5k_stop(struct ieee80211_hw *hw);
|
||||
|
||||
void ath5k_beacon_update_timers(struct ath5k_hw *ah, u64 bc_tsf);
|
||||
int ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
|
||||
void ath5k_beacon_config(struct ath5k_hw *ah);
|
||||
void ath5k_set_beacon_filter(struct ieee80211_hw *hw, bool enable);
|
||||
|
||||
void ath5k_update_bssid_mask_and_opmode(struct ath5k_hw *ah,
|
||||
struct ieee80211_vif *vif);
|
||||
int ath5k_chan_set(struct ath5k_hw *ah, struct ieee80211_channel *chan);
|
||||
void ath5k_txbuf_free_skb(struct ath5k_hw *ah, struct ath5k_buf *bf);
|
||||
void ath5k_rxbuf_free_skb(struct ath5k_hw *ah, struct ath5k_buf *bf);
|
||||
void ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
|
||||
struct ath5k_txq *txq);
|
||||
|
||||
const char *ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val);
|
||||
|
||||
int ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops);
|
||||
void ath5k_deinit_ah(struct ath5k_hw *ah);
|
||||
|
||||
/* Check whether BSSID mask is supported */
|
||||
#define ath5k_hw_hasbssidmask(_ah) (ah->ah_version == AR5K_AR5212)
|
||||
|
@ -87,4 +116,4 @@ void ath5k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif);
|
|||
/* Check whether virtual EOL is supported */
|
||||
#define ath5k_hw_hasveol(_ah) (ah->ah_version != AR5K_AR5210)
|
||||
|
||||
#endif
|
||||
#endif /* _DEV_ATH5K_BASE_H */
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include "ath5k.h"
|
||||
#include "reg.h"
|
||||
#include "debug.h"
|
||||
#include "base.h"
|
||||
#include "../regd.h"
|
||||
|
||||
/*
|
||||
* Fill the capabilities struct
|
||||
|
|
|
@ -58,19 +58,18 @@
|
|||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*/
|
||||
|
||||
#include "base.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/list.h>
|
||||
#include "debug.h"
|
||||
#include "ath5k.h"
|
||||
#include "reg.h"
|
||||
#include "base.h"
|
||||
|
||||
static unsigned int ath5k_debug;
|
||||
module_param_named(debug, ath5k_debug, uint, 0);
|
||||
|
||||
|
||||
#ifdef CONFIG_ATH5K_DEBUG
|
||||
|
||||
#include <linux/seq_file.h>
|
||||
#include "reg.h"
|
||||
#include "ani.h"
|
||||
|
||||
static int ath5k_debugfs_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
file->private_data = inode->i_private;
|
||||
|
@ -1031,5 +1030,3 @@ ath5k_debug_printtxbuf(struct ath5k_hw *ah, struct ath5k_buf *bf)
|
|||
td->tx_stat.tx_status_0, td->tx_stat.tx_status_1,
|
||||
done ? ' ' : (ts.ts_status == 0) ? '*' : '!');
|
||||
}
|
||||
|
||||
#endif /* ifdef CONFIG_ATH5K_DEBUG */
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include "ath5k.h"
|
||||
#include "reg.h"
|
||||
#include "debug.h"
|
||||
#include "base.h"
|
||||
|
||||
|
||||
/************************\
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
#include "ath5k.h"
|
||||
#include "reg.h"
|
||||
#include "debug.h"
|
||||
#include "base.h"
|
||||
|
||||
|
||||
/*********\
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
#include "ath5k.h"
|
||||
#include "reg.h"
|
||||
#include "debug.h"
|
||||
#include "base.h"
|
||||
|
||||
|
||||
/******************\
|
||||
|
@ -1780,13 +1779,12 @@ ath5k_eeprom_detach(struct ath5k_hw *ah)
|
|||
int
|
||||
ath5k_eeprom_mode_from_channel(struct ieee80211_channel *channel)
|
||||
{
|
||||
switch (channel->hw_value & CHANNEL_MODES) {
|
||||
case CHANNEL_A:
|
||||
case CHANNEL_XR:
|
||||
switch (channel->hw_value) {
|
||||
case AR5K_MODE_11A:
|
||||
return AR5K_EEPROM_MODE_11A;
|
||||
case CHANNEL_G:
|
||||
case AR5K_MODE_11G:
|
||||
return AR5K_EEPROM_MODE_11G;
|
||||
case CHANNEL_B:
|
||||
case AR5K_MODE_11B:
|
||||
return AR5K_EEPROM_MODE_11B;
|
||||
default:
|
||||
return -1;
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include "ath5k.h"
|
||||
#include "reg.h"
|
||||
#include "debug.h"
|
||||
#include "base.h"
|
||||
|
||||
/*
|
||||
* Set led state
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include "ath5k.h"
|
||||
#include "reg.h"
|
||||
#include "debug.h"
|
||||
#include "base.h"
|
||||
|
||||
/*
|
||||
* Mode-independent initial register writes
|
||||
|
|
|
@ -41,7 +41,6 @@
|
|||
|
||||
#include <linux/pci.h>
|
||||
#include "ath5k.h"
|
||||
#include "base.h"
|
||||
|
||||
#define ATH_SDEVICE(subv, subd) \
|
||||
.vendor = PCI_ANY_ID, .device = PCI_ANY_ID, \
|
||||
|
|
|
@ -41,8 +41,10 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <net/mac80211.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "ath5k.h"
|
||||
#include "base.h"
|
||||
#include "reg.h"
|
||||
|
||||
|
@ -137,11 +139,8 @@ ath5k_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
|||
/* Any MAC address is fine, all others are included through the
|
||||
* filter.
|
||||
*/
|
||||
memcpy(&ah->lladdr, vif->addr, ETH_ALEN);
|
||||
ath5k_hw_set_lladdr(ah, vif->addr);
|
||||
|
||||
memcpy(&avf->lladdr, vif->addr, ETH_ALEN);
|
||||
|
||||
ath5k_update_bssid_mask_and_opmode(ah, vif);
|
||||
ret = 0;
|
||||
end:
|
||||
|
|
|
@ -261,7 +261,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
|
|||
ah->iobase = mem; /* So we can unmap it on detach */
|
||||
|
||||
/* Initialize */
|
||||
ret = ath5k_init_softc(ah, &ath_pci_bus_ops);
|
||||
ret = ath5k_init_ah(ah, &ath_pci_bus_ops);
|
||||
if (ret)
|
||||
goto err_free;
|
||||
|
||||
|
@ -287,7 +287,7 @@ ath5k_pci_remove(struct pci_dev *pdev)
|
|||
struct ieee80211_hw *hw = pci_get_drvdata(pdev);
|
||||
struct ath5k_hw *ah = hw->priv;
|
||||
|
||||
ath5k_deinit_softc(ah);
|
||||
ath5k_deinit_ah(ah);
|
||||
pci_iounmap(pdev, ah->iobase);
|
||||
pci_release_region(pdev, 0);
|
||||
pci_disable_device(pdev);
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
#include "ath5k.h"
|
||||
#include "reg.h"
|
||||
#include "debug.h"
|
||||
#include "base.h"
|
||||
|
||||
/*
|
||||
* AR5212+ can use higher rates for ack transmission
|
||||
|
@ -152,7 +151,7 @@ unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah)
|
|||
case AR5K_BWMODE_DEFAULT:
|
||||
default:
|
||||
slot_time = AR5K_INIT_SLOT_TIME_DEFAULT;
|
||||
if ((channel->hw_value & CHANNEL_CCK) && !ah->ah_short_slot)
|
||||
if ((channel->hw_value == AR5K_MODE_11B) && !ah->ah_short_slot)
|
||||
slot_time = AR5K_INIT_SLOT_TIME_B;
|
||||
break;
|
||||
}
|
||||
|
@ -183,7 +182,7 @@ unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah)
|
|||
case AR5K_BWMODE_DEFAULT:
|
||||
sifs = AR5K_INIT_SIFS_DEFAULT_BG;
|
||||
default:
|
||||
if (channel->hw_value & CHANNEL_5GHZ)
|
||||
if (channel->band == IEEE80211_BAND_5GHZ)
|
||||
sifs = AR5K_INIT_SIFS_DEFAULT_A;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -26,9 +26,9 @@
|
|||
|
||||
#include "ath5k.h"
|
||||
#include "reg.h"
|
||||
#include "base.h"
|
||||
#include "rfbuffer.h"
|
||||
#include "rfgain.h"
|
||||
#include "../regd.h"
|
||||
|
||||
|
||||
/******************\
|
||||
|
@ -38,7 +38,7 @@
|
|||
/*
|
||||
* Get the PHY Chip revision
|
||||
*/
|
||||
u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan)
|
||||
u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, enum ieee80211_band band)
|
||||
{
|
||||
unsigned int i;
|
||||
u32 srev;
|
||||
|
@ -47,11 +47,11 @@ u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan)
|
|||
/*
|
||||
* Set the radio chip access register
|
||||
*/
|
||||
switch (chan) {
|
||||
case CHANNEL_2GHZ:
|
||||
switch (band) {
|
||||
case IEEE80211_BAND_2GHZ:
|
||||
ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_2GHZ, AR5K_PHY(0));
|
||||
break;
|
||||
case CHANNEL_5GHZ:
|
||||
case IEEE80211_BAND_5GHZ:
|
||||
ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
|
||||
break;
|
||||
default:
|
||||
|
@ -84,14 +84,16 @@ u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan)
|
|||
/*
|
||||
* Check if a channel is supported
|
||||
*/
|
||||
bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags)
|
||||
bool ath5k_channel_ok(struct ath5k_hw *ah, struct ieee80211_channel *channel)
|
||||
{
|
||||
u16 freq = channel->center_freq;
|
||||
|
||||
/* Check if the channel is in our supported range */
|
||||
if (flags & CHANNEL_2GHZ) {
|
||||
if (channel->band == IEEE80211_BAND_2GHZ) {
|
||||
if ((freq >= ah->ah_capabilities.cap_range.range_2ghz_min) &&
|
||||
(freq <= ah->ah_capabilities.cap_range.range_2ghz_max))
|
||||
return true;
|
||||
} else if (flags & CHANNEL_5GHZ)
|
||||
} else if (channel->band == IEEE80211_BAND_5GHZ)
|
||||
if ((freq >= ah->ah_capabilities.cap_range.range_5ghz_min) &&
|
||||
(freq <= ah->ah_capabilities.cap_range.range_5ghz_max))
|
||||
return true;
|
||||
|
@ -224,7 +226,7 @@ static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah,
|
|||
ds_coef_exp, ds_coef_man, clock;
|
||||
|
||||
BUG_ON(!(ah->ah_version == AR5K_AR5212) ||
|
||||
!(channel->hw_value & CHANNEL_OFDM));
|
||||
(channel->hw_value == AR5K_MODE_11B));
|
||||
|
||||
/* Get coefficient
|
||||
* ALGO: coef = (5 * clock / carrier_freq) / 2
|
||||
|
@ -298,7 +300,7 @@ static void ath5k_hw_wait_for_synth(struct ath5k_hw *ah,
|
|||
u32 delay;
|
||||
delay = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) &
|
||||
AR5K_PHY_RX_DELAY_M;
|
||||
delay = (channel->hw_value & CHANNEL_CCK) ?
|
||||
delay = (channel->hw_value == AR5K_MODE_11B) ?
|
||||
((delay << 2) / 22) : (delay / 10);
|
||||
if (ah->ah_bwmode == AR5K_BWMODE_10MHZ)
|
||||
delay = delay << 1;
|
||||
|
@ -798,9 +800,9 @@ static int ath5k_hw_rfregs_init(struct ath5k_hw *ah,
|
|||
}
|
||||
|
||||
/* Set Output and Driver bias current (OB/DB) */
|
||||
if (channel->hw_value & CHANNEL_2GHZ) {
|
||||
if (channel->band == IEEE80211_BAND_2GHZ) {
|
||||
|
||||
if (channel->hw_value & CHANNEL_CCK)
|
||||
if (channel->hw_value == AR5K_MODE_11B)
|
||||
ee_mode = AR5K_EEPROM_MODE_11B;
|
||||
else
|
||||
ee_mode = AR5K_EEPROM_MODE_11G;
|
||||
|
@ -825,7 +827,7 @@ static int ath5k_hw_rfregs_init(struct ath5k_hw *ah,
|
|||
AR5K_RF_DB_2GHZ, true);
|
||||
|
||||
/* RF5111 always needs OB/DB for 5GHz, even if we use 2GHz */
|
||||
} else if ((channel->hw_value & CHANNEL_5GHZ) ||
|
||||
} else if ((channel->band == IEEE80211_BAND_5GHZ) ||
|
||||
(ah->ah_radio == AR5K_RF5111)) {
|
||||
|
||||
/* For 11a, Turbo and XR we need to choose
|
||||
|
@ -857,7 +859,7 @@ static int ath5k_hw_rfregs_init(struct ath5k_hw *ah,
|
|||
if (ah->ah_radio == AR5K_RF5111) {
|
||||
|
||||
/* Set gain_F settings according to current step */
|
||||
if (channel->hw_value & CHANNEL_OFDM) {
|
||||
if (channel->hw_value != AR5K_MODE_11B) {
|
||||
|
||||
AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL,
|
||||
AR5K_PHY_FRAME_CTL_TX_CLIP,
|
||||
|
@ -914,7 +916,7 @@ static int ath5k_hw_rfregs_init(struct ath5k_hw *ah,
|
|||
if (ah->ah_radio == AR5K_RF5112) {
|
||||
|
||||
/* Set gain_F settings according to current step */
|
||||
if (channel->hw_value & CHANNEL_OFDM) {
|
||||
if (channel->hw_value != AR5K_MODE_11B) {
|
||||
|
||||
ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[0],
|
||||
AR5K_RF_MIXGAIN_OVR, true);
|
||||
|
@ -1026,7 +1028,7 @@ static int ath5k_hw_rfregs_init(struct ath5k_hw *ah,
|
|||
}
|
||||
|
||||
if (ah->ah_radio == AR5K_RF5413 &&
|
||||
channel->hw_value & CHANNEL_2GHZ) {
|
||||
channel->band == IEEE80211_BAND_2GHZ) {
|
||||
|
||||
ath5k_hw_rfb_op(ah, rf_regs, 1, AR5K_RF_DERBY_CHAN_SEL_MODE,
|
||||
true);
|
||||
|
@ -1138,7 +1140,7 @@ static int ath5k_hw_rf5111_channel(struct ath5k_hw *ah,
|
|||
*/
|
||||
data0 = data1 = 0;
|
||||
|
||||
if (channel->hw_value & CHANNEL_2GHZ) {
|
||||
if (channel->band == IEEE80211_BAND_2GHZ) {
|
||||
/* Map 2GHz channel to 5GHz Atheros channel ID */
|
||||
ret = ath5k_hw_rf5111_chan2athchan(
|
||||
ieee80211_frequency_to_channel(channel->center_freq),
|
||||
|
@ -1265,10 +1267,9 @@ static int ath5k_hw_channel(struct ath5k_hw *ah,
|
|||
int ret;
|
||||
/*
|
||||
* Check bounds supported by the PHY (we don't care about regulatory
|
||||
* restrictions at this point). Note: hw_value already has the band
|
||||
* (CHANNEL_2GHZ, or CHANNEL_5GHZ) so we inform ath5k_channel_ok()
|
||||
* of the band by that */
|
||||
if (!ath5k_channel_ok(ah, channel->center_freq, channel->hw_value)) {
|
||||
* restrictions at this point).
|
||||
*/
|
||||
if (!ath5k_channel_ok(ah, channel)) {
|
||||
ATH5K_ERR(ah,
|
||||
"channel frequency (%u MHz) out of supported "
|
||||
"band range\n",
|
||||
|
@ -1614,7 +1615,7 @@ int ath5k_hw_phy_calibrate(struct ath5k_hw *ah,
|
|||
ret = ath5k_hw_rf511x_iq_calibrate(ah);
|
||||
|
||||
if ((ah->ah_radio == AR5K_RF5111 || ah->ah_radio == AR5K_RF5112) &&
|
||||
(channel->hw_value & CHANNEL_OFDM))
|
||||
(channel->hw_value != AR5K_MODE_11B))
|
||||
ath5k_hw_request_rfgain_probe(ah);
|
||||
|
||||
return ret;
|
||||
|
@ -1641,7 +1642,7 @@ ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah,
|
|||
/* Convert current frequency to fbin value (the same way channels
|
||||
* are stored on EEPROM, check out ath5k_eeprom_bin2freq) and scale
|
||||
* up by 2 so we can compare it later */
|
||||
if (channel->hw_value & CHANNEL_2GHZ) {
|
||||
if (channel->band == IEEE80211_BAND_2GHZ) {
|
||||
chan_fbin = (channel->center_freq - 2300) * 10;
|
||||
freq_band = AR5K_EEPROM_BAND_2GHZ;
|
||||
} else {
|
||||
|
@ -1703,7 +1704,7 @@ ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah,
|
|||
spur_freq_sigma_delta = (spur_delta_phase >> 10);
|
||||
symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz / 4;
|
||||
default:
|
||||
if (channel->hw_value == CHANNEL_A) {
|
||||
if (channel->band == IEEE80211_BAND_5GHZ) {
|
||||
/* Both sample_freq and chip_freq are 40MHz */
|
||||
spur_delta_phase = (spur_offset << 17) / 25;
|
||||
spur_freq_sigma_delta =
|
||||
|
@ -2226,15 +2227,20 @@ ath5k_get_chan_pcal_surrounding_piers(struct ath5k_hw *ah,
|
|||
idx_l = 0;
|
||||
idx_r = 0;
|
||||
|
||||
if (!(channel->hw_value & CHANNEL_OFDM)) {
|
||||
pcinfo = ee->ee_pwr_cal_b;
|
||||
mode = AR5K_EEPROM_MODE_11B;
|
||||
} else if (channel->hw_value & CHANNEL_2GHZ) {
|
||||
pcinfo = ee->ee_pwr_cal_g;
|
||||
mode = AR5K_EEPROM_MODE_11G;
|
||||
} else {
|
||||
switch (channel->hw_value) {
|
||||
case AR5K_EEPROM_MODE_11A:
|
||||
pcinfo = ee->ee_pwr_cal_a;
|
||||
mode = AR5K_EEPROM_MODE_11A;
|
||||
break;
|
||||
case AR5K_EEPROM_MODE_11B:
|
||||
pcinfo = ee->ee_pwr_cal_b;
|
||||
mode = AR5K_EEPROM_MODE_11B;
|
||||
break;
|
||||
case AR5K_EEPROM_MODE_11G:
|
||||
default:
|
||||
pcinfo = ee->ee_pwr_cal_g;
|
||||
mode = AR5K_EEPROM_MODE_11G;
|
||||
break;
|
||||
}
|
||||
max = ee->ee_n_piers[mode] - 1;
|
||||
|
||||
|
@ -2303,15 +2309,20 @@ ath5k_get_rate_pcal_data(struct ath5k_hw *ah,
|
|||
idx_l = 0;
|
||||
idx_r = 0;
|
||||
|
||||
if (!(channel->hw_value & CHANNEL_OFDM)) {
|
||||
rpinfo = ee->ee_rate_tpwr_b;
|
||||
mode = AR5K_EEPROM_MODE_11B;
|
||||
} else if (channel->hw_value & CHANNEL_2GHZ) {
|
||||
rpinfo = ee->ee_rate_tpwr_g;
|
||||
mode = AR5K_EEPROM_MODE_11G;
|
||||
} else {
|
||||
switch (channel->hw_value) {
|
||||
case AR5K_MODE_11A:
|
||||
rpinfo = ee->ee_rate_tpwr_a;
|
||||
mode = AR5K_EEPROM_MODE_11A;
|
||||
break;
|
||||
case AR5K_MODE_11B:
|
||||
rpinfo = ee->ee_rate_tpwr_b;
|
||||
mode = AR5K_EEPROM_MODE_11B;
|
||||
break;
|
||||
case AR5K_MODE_11G:
|
||||
default:
|
||||
rpinfo = ee->ee_rate_tpwr_g;
|
||||
mode = AR5K_EEPROM_MODE_11G;
|
||||
break;
|
||||
}
|
||||
max = ee->ee_rate_target_pwr_num[mode] - 1;
|
||||
|
||||
|
@ -2392,24 +2403,22 @@ ath5k_get_max_ctl_power(struct ath5k_hw *ah,
|
|||
|
||||
ctl_mode = ath_regd_get_band_ctl(regulatory, channel->band);
|
||||
|
||||
switch (channel->hw_value & CHANNEL_MODES) {
|
||||
case CHANNEL_A:
|
||||
switch (channel->hw_value) {
|
||||
case AR5K_MODE_11A:
|
||||
if (ah->ah_bwmode == AR5K_BWMODE_40MHZ)
|
||||
ctl_mode |= AR5K_CTL_TURBO;
|
||||
else
|
||||
ctl_mode |= AR5K_CTL_11A;
|
||||
break;
|
||||
case CHANNEL_G:
|
||||
case AR5K_MODE_11G:
|
||||
if (ah->ah_bwmode == AR5K_BWMODE_40MHZ)
|
||||
ctl_mode |= AR5K_CTL_TURBOG;
|
||||
else
|
||||
ctl_mode |= AR5K_CTL_11G;
|
||||
break;
|
||||
case CHANNEL_B:
|
||||
case AR5K_MODE_11B:
|
||||
ctl_mode |= AR5K_CTL_11B;
|
||||
break;
|
||||
case CHANNEL_XR:
|
||||
/* Fall through */
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
@ -3292,7 +3301,7 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
|
|||
|
||||
/* Write OFDM timings on 5212*/
|
||||
if (ah->ah_version == AR5K_AR5212 &&
|
||||
channel->hw_value & CHANNEL_OFDM) {
|
||||
channel->hw_value != AR5K_MODE_11B) {
|
||||
|
||||
ret = ath5k_hw_write_ofdm_timings(ah, channel);
|
||||
if (ret)
|
||||
|
|
|
@ -23,7 +23,6 @@ Queue Control Unit, DFS Control Unit Functions
|
|||
#include "ath5k.h"
|
||||
#include "reg.h"
|
||||
#include "debug.h"
|
||||
#include "base.h"
|
||||
|
||||
|
||||
/******************\
|
||||
|
@ -185,13 +184,6 @@ int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
|
|||
case AR5K_TX_QUEUE_CAB:
|
||||
queue = AR5K_TX_QUEUE_ID_CAB;
|
||||
break;
|
||||
case AR5K_TX_QUEUE_XR_DATA:
|
||||
if (ah->ah_version != AR5K_AR5212)
|
||||
ATH5K_ERR(ah,
|
||||
"XR data queues only supported in"
|
||||
" 5212!\n");
|
||||
queue = AR5K_TX_QUEUE_ID_XR_DATA;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -544,7 +536,7 @@ int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time)
|
|||
*
|
||||
* Also we have different lowest rate for 802.11a
|
||||
*/
|
||||
if (channel->hw_value & CHANNEL_5GHZ)
|
||||
if (channel->band == IEEE80211_BAND_5GHZ)
|
||||
rate = &ah->sbands[IEEE80211_BAND_5GHZ].bitrates[0];
|
||||
else
|
||||
rate = &ah->sbands[IEEE80211_BAND_2GHZ].bitrates[0];
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include "ath5k.h"
|
||||
#include "reg.h"
|
||||
#include "base.h"
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
|
@ -102,12 +101,18 @@ static void ath5k_hw_init_core_clock(struct ath5k_hw *ah)
|
|||
/*
|
||||
* Set core clock frequency
|
||||
*/
|
||||
if (channel->hw_value & CHANNEL_5GHZ)
|
||||
clock = 40; /* 802.11a */
|
||||
else if (channel->hw_value & CHANNEL_CCK)
|
||||
clock = 22; /* 802.11b */
|
||||
else
|
||||
clock = 44; /* 802.11g */
|
||||
switch (channel->hw_value) {
|
||||
case AR5K_MODE_11A:
|
||||
clock = 40;
|
||||
break;
|
||||
case AR5K_MODE_11B:
|
||||
clock = 22;
|
||||
break;
|
||||
case AR5K_MODE_11G:
|
||||
default:
|
||||
clock = 44;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Use clock multiplier for non-default
|
||||
* bwmode */
|
||||
|
@ -581,8 +586,9 @@ int ath5k_hw_on_hold(struct ath5k_hw *ah)
|
|||
|
||||
/*
|
||||
* Bring up MAC + PHY Chips and program PLL
|
||||
* Channel is NULL for the initial wakeup.
|
||||
*/
|
||||
int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
|
||||
int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel)
|
||||
{
|
||||
struct pci_dev *pdev = ah->pdev;
|
||||
u32 turbo, mode, clock, bus_flags;
|
||||
|
@ -592,7 +598,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
|
|||
mode = 0;
|
||||
clock = 0;
|
||||
|
||||
if ((ath5k_get_bus_type(ah) != ATH_AHB) || !initial) {
|
||||
if ((ath5k_get_bus_type(ah) != ATH_AHB) || channel) {
|
||||
/* Wakeup the device */
|
||||
ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
|
||||
if (ret) {
|
||||
|
@ -652,7 +658,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
|
|||
|
||||
/* On initialization skip PLL programming since we don't have
|
||||
* a channel / mode set yet */
|
||||
if (initial)
|
||||
if (!channel)
|
||||
return 0;
|
||||
|
||||
if (ah->ah_version != AR5K_AR5210) {
|
||||
|
@ -668,13 +674,13 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
|
|||
clock = AR5K_PHY_PLL_RF5111; /*Zero*/
|
||||
}
|
||||
|
||||
if (flags & CHANNEL_2GHZ) {
|
||||
if (channel->band == IEEE80211_BAND_2GHZ) {
|
||||
mode |= AR5K_PHY_MODE_FREQ_2GHZ;
|
||||
clock |= AR5K_PHY_PLL_44MHZ;
|
||||
|
||||
if (flags & CHANNEL_CCK) {
|
||||
if (channel->hw_value == AR5K_MODE_11B) {
|
||||
mode |= AR5K_PHY_MODE_MOD_CCK;
|
||||
} else if (flags & CHANNEL_OFDM) {
|
||||
} else {
|
||||
/* XXX Dynamic OFDM/CCK is not supported by the
|
||||
* AR5211 so we set MOD_OFDM for plain g (no
|
||||
* CCK headers) operation. We need to test
|
||||
|
@ -686,27 +692,16 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
|
|||
mode |= AR5K_PHY_MODE_MOD_OFDM;
|
||||
else
|
||||
mode |= AR5K_PHY_MODE_MOD_DYN;
|
||||
} else {
|
||||
ATH5K_ERR(ah,
|
||||
"invalid radio modulation mode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
} else if (flags & CHANNEL_5GHZ) {
|
||||
mode |= AR5K_PHY_MODE_FREQ_5GHZ;
|
||||
} else if (channel->band == IEEE80211_BAND_5GHZ) {
|
||||
mode |= (AR5K_PHY_MODE_FREQ_5GHZ |
|
||||
AR5K_PHY_MODE_MOD_OFDM);
|
||||
|
||||
/* Different PLL setting for 5413 */
|
||||
if (ah->ah_radio == AR5K_RF5413)
|
||||
clock = AR5K_PHY_PLL_40MHZ_5413;
|
||||
else
|
||||
clock |= AR5K_PHY_PLL_40MHZ;
|
||||
|
||||
if (flags & CHANNEL_OFDM)
|
||||
mode |= AR5K_PHY_MODE_MOD_OFDM;
|
||||
else {
|
||||
ATH5K_ERR(ah,
|
||||
"invalid radio modulation mode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
ATH5K_ERR(ah, "invalid radio frequency mode\n");
|
||||
return -EINVAL;
|
||||
|
@ -822,7 +817,7 @@ static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah,
|
|||
u32 data;
|
||||
ath5k_hw_reg_write(ah, AR5K_PHY_CCKTXCTL_WORLD,
|
||||
AR5K_PHY_CCKTXCTL);
|
||||
if (channel->hw_value & CHANNEL_5GHZ)
|
||||
if (channel->band == IEEE80211_BAND_5GHZ)
|
||||
data = 0xffb81020;
|
||||
else
|
||||
data = 0xffb80d20;
|
||||
|
@ -905,7 +900,7 @@ static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
|
|||
/* Set CCK to OFDM power delta on tx power
|
||||
* adjustment register */
|
||||
if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) {
|
||||
if (channel->hw_value == CHANNEL_G)
|
||||
if (channel->hw_value == AR5K_MODE_11G)
|
||||
ath5k_hw_reg_write(ah,
|
||||
AR5K_REG_SM((ee->ee_cck_ofdm_gain_delta * -1),
|
||||
AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA) |
|
||||
|
@ -1084,37 +1079,23 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
|
|||
ret = 0;
|
||||
}
|
||||
|
||||
switch (channel->hw_value & CHANNEL_MODES) {
|
||||
case CHANNEL_A:
|
||||
mode = AR5K_MODE_11A;
|
||||
mode = channel->hw_value;
|
||||
switch (mode) {
|
||||
case AR5K_MODE_11A:
|
||||
break;
|
||||
case CHANNEL_G:
|
||||
|
||||
case AR5K_MODE_11G:
|
||||
if (ah->ah_version <= AR5K_AR5211) {
|
||||
ATH5K_ERR(ah,
|
||||
"G mode not available on 5210/5211");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mode = AR5K_MODE_11G;
|
||||
break;
|
||||
case CHANNEL_B:
|
||||
|
||||
case AR5K_MODE_11B:
|
||||
if (ah->ah_version < AR5K_AR5211) {
|
||||
ATH5K_ERR(ah,
|
||||
"B mode not available on 5210");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mode = AR5K_MODE_11B;
|
||||
break;
|
||||
case CHANNEL_XR:
|
||||
if (ah->ah_version == AR5K_AR5211) {
|
||||
ATH5K_ERR(ah,
|
||||
"XR mode not available on 5211");
|
||||
return -EINVAL;
|
||||
}
|
||||
mode = AR5K_MODE_XR;
|
||||
break;
|
||||
default:
|
||||
ATH5K_ERR(ah,
|
||||
|
@ -1200,7 +1181,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
|
|||
}
|
||||
|
||||
/* Wakeup the device */
|
||||
ret = ath5k_hw_nic_wakeup(ah, channel->hw_value, false);
|
||||
ret = ath5k_hw_nic_wakeup(ah, channel);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*/
|
||||
|
||||
#include "base.h"
|
||||
#include "ath5k.h"
|
||||
|
||||
|
||||
static inline void ath5k_rfkill_disable(struct ath5k_hw *ah)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "base.h"
|
||||
#include "ath5k.h"
|
||||
#include "reg.h"
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#define __TRACE_ATH5K_H
|
||||
|
||||
#include <linux/tracepoint.h>
|
||||
#include "base.h"
|
||||
|
||||
#ifndef CONFIG_ATH5K_TRACER
|
||||
#undef TRACE_EVENT
|
||||
|
@ -11,6 +10,8 @@ static inline void trace_ ## name(proto) {}
|
|||
#endif
|
||||
|
||||
struct sk_buff;
|
||||
struct ath5k_txq;
|
||||
struct ath5k_tx_status;
|
||||
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM ath5k
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
config ATH6KL
|
||||
tristate "Atheros ath6kl support"
|
||||
depends on MMC
|
||||
depends on CFG80211
|
||||
---help---
|
||||
This module adds support for wireless adapters based on
|
||||
Atheros AR6003 chipset running over SDIO. If you choose to
|
||||
build it as a module, it will be called ath6kl. Pls note
|
||||
that AR6002 and AR6001 are not supported by this driver.
|
||||
|
||||
config ATH6KL_DEBUG
|
||||
bool "Atheros ath6kl debugging"
|
||||
depends on ATH6KL
|
||||
---help---
|
||||
Enables debug support
|
|
@ -0,0 +1,35 @@
|
|||
#------------------------------------------------------------------------------
|
||||
# Copyright (c) 2004-2010 Atheros Communications Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
#
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#
|
||||
#
|
||||
# Author(s): ="Atheros"
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
obj-$(CONFIG_ATH6KL) := ath6kl.o
|
||||
ath6kl-y += debug.o
|
||||
ath6kl-y += htc_hif.o
|
||||
ath6kl-y += htc.o
|
||||
ath6kl-y += bmi.o
|
||||
ath6kl-y += cfg80211.o
|
||||
ath6kl-y += init.o
|
||||
ath6kl-y += main.o
|
||||
ath6kl-y += txrx.o
|
||||
ath6kl-y += wmi.o
|
||||
ath6kl-y += node.o
|
||||
ath6kl-y += sdio.o
|
|
@ -0,0 +1,692 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2011 Atheros Communications 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 "core.h"
|
||||
#include "hif-ops.h"
|
||||
#include "target.h"
|
||||
#include "debug.h"
|
||||
|
||||
static int ath6kl_get_bmi_cmd_credits(struct ath6kl *ar)
|
||||
{
|
||||
u32 addr;
|
||||
unsigned long timeout;
|
||||
int ret;
|
||||
|
||||
ar->bmi.cmd_credits = 0;
|
||||
|
||||
/* Read the counter register to get the command credits */
|
||||
addr = COUNT_DEC_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 4;
|
||||
|
||||
timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT);
|
||||
while (time_before(jiffies, timeout) && !ar->bmi.cmd_credits) {
|
||||
|
||||
/*
|
||||
* Hit the credit counter with a 4-byte access, the first byte
|
||||
* read will hit the counter and cause a decrement, while the
|
||||
* remaining 3 bytes has no effect. The rationale behind this
|
||||
* is to make all HIF accesses 4-byte aligned.
|
||||
*/
|
||||
ret = hif_read_write_sync(ar, addr,
|
||||
(u8 *)&ar->bmi.cmd_credits, 4,
|
||||
HIF_RD_SYNC_BYTE_INC);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to decrement the command credit count register: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* The counter is only 8 bits.
|
||||
* Ignore anything in the upper 3 bytes
|
||||
*/
|
||||
ar->bmi.cmd_credits &= 0xFF;
|
||||
}
|
||||
|
||||
if (!ar->bmi.cmd_credits) {
|
||||
ath6kl_err("bmi communication timeout\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kl_bmi_get_rx_lkahd(struct ath6kl *ar, bool need_timeout)
|
||||
{
|
||||
unsigned long timeout;
|
||||
u32 rx_word = 0;
|
||||
int ret = 0;
|
||||
|
||||
timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT);
|
||||
while ((!need_timeout || time_before(jiffies, timeout)) && !rx_word) {
|
||||
ret = hif_read_write_sync(ar, RX_LOOKAHEAD_VALID_ADDRESS,
|
||||
(u8 *)&rx_word, sizeof(rx_word),
|
||||
HIF_RD_SYNC_BYTE_INC);
|
||||
if (ret) {
|
||||
ath6kl_err("unable to read RX_LOOKAHEAD_VALID\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* all we really want is one bit */
|
||||
rx_word &= (1 << ENDPOINT1);
|
||||
}
|
||||
|
||||
if (!rx_word) {
|
||||
ath6kl_err("bmi_recv_buf FIFO empty\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath6kl_bmi_send_buf(struct ath6kl *ar, u8 *buf, u32 len)
|
||||
{
|
||||
int ret;
|
||||
u32 addr;
|
||||
|
||||
ret = ath6kl_get_bmi_cmd_credits(ar);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
addr = ar->mbox_info.htc_addr;
|
||||
|
||||
ret = hif_read_write_sync(ar, addr, buf, len,
|
||||
HIF_WR_SYNC_BYTE_INC);
|
||||
if (ret)
|
||||
ath6kl_err("unable to send the bmi data to the device\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath6kl_bmi_recv_buf(struct ath6kl *ar,
|
||||
u8 *buf, u32 len, bool want_timeout)
|
||||
{
|
||||
int ret;
|
||||
u32 addr;
|
||||
|
||||
/*
|
||||
* During normal bootup, small reads may be required.
|
||||
* Rather than issue an HIF Read and then wait as the Target
|
||||
* adds successive bytes to the FIFO, we wait here until
|
||||
* we know that response data is available.
|
||||
*
|
||||
* This allows us to cleanly timeout on an unexpected
|
||||
* Target failure rather than risk problems at the HIF level.
|
||||
* In particular, this avoids SDIO timeouts and possibly garbage
|
||||
* data on some host controllers. And on an interconnect
|
||||
* such as Compact Flash (as well as some SDIO masters) which
|
||||
* does not provide any indication on data timeout, it avoids
|
||||
* a potential hang or garbage response.
|
||||
*
|
||||
* Synchronization is more difficult for reads larger than the
|
||||
* size of the MBOX FIFO (128B), because the Target is unable
|
||||
* to push the 129th byte of data until AFTER the Host posts an
|
||||
* HIF Read and removes some FIFO data. So for large reads the
|
||||
* Host proceeds to post an HIF Read BEFORE all the data is
|
||||
* actually available to read. Fortunately, large BMI reads do
|
||||
* not occur in practice -- they're supported for debug/development.
|
||||
*
|
||||
* So Host/Target BMI synchronization is divided into these cases:
|
||||
* CASE 1: length < 4
|
||||
* Should not happen
|
||||
*
|
||||
* CASE 2: 4 <= length <= 128
|
||||
* Wait for first 4 bytes to be in FIFO
|
||||
* If CONSERVATIVE_BMI_READ is enabled, also wait for
|
||||
* a BMI command credit, which indicates that the ENTIRE
|
||||
* response is available in the the FIFO
|
||||
*
|
||||
* CASE 3: length > 128
|
||||
* Wait for the first 4 bytes to be in FIFO
|
||||
*
|
||||
* For most uses, a small timeout should be sufficient and we will
|
||||
* usually see a response quickly; but there may be some unusual
|
||||
* (debug) cases of BMI_EXECUTE where we want an larger timeout.
|
||||
* For now, we use an unbounded busy loop while waiting for
|
||||
* BMI_EXECUTE.
|
||||
*
|
||||
* If BMI_EXECUTE ever needs to support longer-latency execution,
|
||||
* especially in production, this code needs to be enhanced to sleep
|
||||
* and yield. Also note that BMI_COMMUNICATION_TIMEOUT is currently
|
||||
* a function of Host processor speed.
|
||||
*/
|
||||
if (len >= 4) { /* NB: Currently, always true */
|
||||
ret = ath6kl_bmi_get_rx_lkahd(ar, want_timeout);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
addr = ar->mbox_info.htc_addr;
|
||||
ret = hif_read_write_sync(ar, addr, buf, len,
|
||||
HIF_RD_SYNC_BYTE_INC);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to read the bmi data from the device: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath6kl_bmi_done(struct ath6kl *ar)
|
||||
{
|
||||
int ret;
|
||||
u32 cid = BMI_DONE;
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath6kl_dbg(ATH6KL_DBG_BMI, "bmi done skipped\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ar->bmi.done_sent = true;
|
||||
|
||||
ret = ath6kl_bmi_send_buf(ar, (u8 *)&cid, sizeof(cid));
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to send bmi done: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ath6kl_bmi_cleanup(ar);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath6kl_bmi_get_target_info(struct ath6kl *ar,
|
||||
struct ath6kl_bmi_target_info *targ_info)
|
||||
{
|
||||
int ret;
|
||||
u32 cid = BMI_GET_TARGET_INFO;
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
ret = ath6kl_bmi_send_buf(ar, (u8 *)&cid, sizeof(cid));
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to send get target info: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ath6kl_bmi_recv_buf(ar, (u8 *)&targ_info->version,
|
||||
sizeof(targ_info->version), true);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to recv target info: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (le32_to_cpu(targ_info->version) == TARGET_VERSION_SENTINAL) {
|
||||
/* Determine how many bytes are in the Target's targ_info */
|
||||
ret = ath6kl_bmi_recv_buf(ar,
|
||||
(u8 *)&targ_info->byte_count,
|
||||
sizeof(targ_info->byte_count),
|
||||
true);
|
||||
if (ret) {
|
||||
ath6kl_err("unable to read target info byte count: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* The target's targ_info doesn't match the host's targ_info.
|
||||
* We need to do some backwards compatibility to make this work.
|
||||
*/
|
||||
if (le32_to_cpu(targ_info->byte_count) != sizeof(*targ_info)) {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Read the remainder of the targ_info */
|
||||
ret = ath6kl_bmi_recv_buf(ar,
|
||||
((u8 *)targ_info) +
|
||||
sizeof(targ_info->byte_count),
|
||||
sizeof(*targ_info) -
|
||||
sizeof(targ_info->byte_count),
|
||||
true);
|
||||
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to read target info (%d bytes): %d\n",
|
||||
targ_info->byte_count, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_BMI, "target info (ver: 0x%x type: 0x%x)\n",
|
||||
targ_info->version, targ_info->type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath6kl_bmi_read(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
|
||||
{
|
||||
u32 cid = BMI_READ_MEMORY;
|
||||
int ret;
|
||||
u32 offset;
|
||||
u32 len_remain, rx_len;
|
||||
u16 size;
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
size = BMI_DATASZ_MAX + sizeof(cid) + sizeof(addr) + sizeof(len);
|
||||
if (size > MAX_BMI_CMDBUF_SZ) {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
memset(ar->bmi.cmd_buf, 0, size);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_BMI,
|
||||
"bmi read memory: device: addr: 0x%x, len: %d\n",
|
||||
addr, len);
|
||||
|
||||
len_remain = len;
|
||||
|
||||
while (len_remain) {
|
||||
rx_len = (len_remain < BMI_DATASZ_MAX) ?
|
||||
len_remain : BMI_DATASZ_MAX;
|
||||
offset = 0;
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
|
||||
offset += sizeof(cid);
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
|
||||
offset += sizeof(addr);
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &rx_len, sizeof(rx_len));
|
||||
offset += sizeof(len);
|
||||
|
||||
ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to write to the device: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, rx_len, true);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to read from the device: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
memcpy(&buf[len - len_remain], ar->bmi.cmd_buf, rx_len);
|
||||
len_remain -= rx_len; addr += rx_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
|
||||
{
|
||||
u32 cid = BMI_WRITE_MEMORY;
|
||||
int ret;
|
||||
u32 offset;
|
||||
u32 len_remain, tx_len;
|
||||
const u32 header = sizeof(cid) + sizeof(addr) + sizeof(len);
|
||||
u8 aligned_buf[BMI_DATASZ_MAX];
|
||||
u8 *src;
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
if ((BMI_DATASZ_MAX + header) > MAX_BMI_CMDBUF_SZ) {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(ar->bmi.cmd_buf, 0, BMI_DATASZ_MAX + header);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_BMI,
|
||||
"bmi write memory: addr: 0x%x, len: %d\n", addr, len);
|
||||
|
||||
len_remain = len;
|
||||
while (len_remain) {
|
||||
src = &buf[len - len_remain];
|
||||
|
||||
if (len_remain < (BMI_DATASZ_MAX - header)) {
|
||||
if (len_remain & 3) {
|
||||
/* align it with 4 bytes */
|
||||
len_remain = len_remain +
|
||||
(4 - (len_remain & 3));
|
||||
memcpy(aligned_buf, src, len_remain);
|
||||
src = aligned_buf;
|
||||
}
|
||||
tx_len = len_remain;
|
||||
} else {
|
||||
tx_len = (BMI_DATASZ_MAX - header);
|
||||
}
|
||||
|
||||
offset = 0;
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
|
||||
offset += sizeof(cid);
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
|
||||
offset += sizeof(addr);
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &tx_len, sizeof(tx_len));
|
||||
offset += sizeof(tx_len);
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), src, tx_len);
|
||||
offset += tx_len;
|
||||
|
||||
ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to write to the device: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
len_remain -= tx_len; addr += tx_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath6kl_bmi_execute(struct ath6kl *ar, u32 addr, u32 *param)
|
||||
{
|
||||
u32 cid = BMI_EXECUTE;
|
||||
int ret;
|
||||
u32 offset;
|
||||
u16 size;
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
size = sizeof(cid) + sizeof(addr) + sizeof(param);
|
||||
if (size > MAX_BMI_CMDBUF_SZ) {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
memset(ar->bmi.cmd_buf, 0, size);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_BMI, "bmi execute: addr: 0x%x, param: %d)\n",
|
||||
addr, *param);
|
||||
|
||||
offset = 0;
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
|
||||
offset += sizeof(cid);
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
|
||||
offset += sizeof(addr);
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), param, sizeof(*param));
|
||||
offset += sizeof(*param);
|
||||
|
||||
ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to write to the device: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, sizeof(*param), false);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to read from the device: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
memcpy(param, ar->bmi.cmd_buf, sizeof(*param));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath6kl_bmi_set_app_start(struct ath6kl *ar, u32 addr)
|
||||
{
|
||||
u32 cid = BMI_SET_APP_START;
|
||||
int ret;
|
||||
u32 offset;
|
||||
u16 size;
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
size = sizeof(cid) + sizeof(addr);
|
||||
if (size > MAX_BMI_CMDBUF_SZ) {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
memset(ar->bmi.cmd_buf, 0, size);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_BMI, "bmi set app start: addr: 0x%x\n", addr);
|
||||
|
||||
offset = 0;
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
|
||||
offset += sizeof(cid);
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
|
||||
offset += sizeof(addr);
|
||||
|
||||
ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to write to the device: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath6kl_bmi_reg_read(struct ath6kl *ar, u32 addr, u32 *param)
|
||||
{
|
||||
u32 cid = BMI_READ_SOC_REGISTER;
|
||||
int ret;
|
||||
u32 offset;
|
||||
u16 size;
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
size = sizeof(cid) + sizeof(addr);
|
||||
if (size > MAX_BMI_CMDBUF_SZ) {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
memset(ar->bmi.cmd_buf, 0, size);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_BMI, "bmi read SOC reg: addr: 0x%x\n", addr);
|
||||
|
||||
offset = 0;
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
|
||||
offset += sizeof(cid);
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
|
||||
offset += sizeof(addr);
|
||||
|
||||
ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to write to the device: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, sizeof(*param), true);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to read from the device: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
memcpy(param, ar->bmi.cmd_buf, sizeof(*param));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath6kl_bmi_reg_write(struct ath6kl *ar, u32 addr, u32 param)
|
||||
{
|
||||
u32 cid = BMI_WRITE_SOC_REGISTER;
|
||||
int ret;
|
||||
u32 offset;
|
||||
u16 size;
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
size = sizeof(cid) + sizeof(addr) + sizeof(param);
|
||||
if (size > MAX_BMI_CMDBUF_SZ) {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
memset(ar->bmi.cmd_buf, 0, size);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_BMI,
|
||||
"bmi write SOC reg: addr: 0x%x, param: %d\n",
|
||||
addr, param);
|
||||
|
||||
offset = 0;
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
|
||||
offset += sizeof(cid);
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
|
||||
offset += sizeof(addr);
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), ¶m, sizeof(param));
|
||||
offset += sizeof(param);
|
||||
|
||||
ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to write to the device: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath6kl_bmi_lz_data(struct ath6kl *ar, u8 *buf, u32 len)
|
||||
{
|
||||
u32 cid = BMI_LZ_DATA;
|
||||
int ret;
|
||||
u32 offset;
|
||||
u32 len_remain, tx_len;
|
||||
const u32 header = sizeof(cid) + sizeof(len);
|
||||
u16 size;
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
size = BMI_DATASZ_MAX + header;
|
||||
if (size > MAX_BMI_CMDBUF_SZ) {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
memset(ar->bmi.cmd_buf, 0, size);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_BMI, "bmi send LZ data: len: %d)\n",
|
||||
len);
|
||||
|
||||
len_remain = len;
|
||||
while (len_remain) {
|
||||
tx_len = (len_remain < (BMI_DATASZ_MAX - header)) ?
|
||||
len_remain : (BMI_DATASZ_MAX - header);
|
||||
|
||||
offset = 0;
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
|
||||
offset += sizeof(cid);
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &tx_len, sizeof(tx_len));
|
||||
offset += sizeof(tx_len);
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &buf[len - len_remain],
|
||||
tx_len);
|
||||
offset += tx_len;
|
||||
|
||||
ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to write to the device: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
len_remain -= tx_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath6kl_bmi_lz_stream_start(struct ath6kl *ar, u32 addr)
|
||||
{
|
||||
u32 cid = BMI_LZ_STREAM_START;
|
||||
int ret;
|
||||
u32 offset;
|
||||
u16 size;
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
size = sizeof(cid) + sizeof(addr);
|
||||
if (size > MAX_BMI_CMDBUF_SZ) {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
memset(ar->bmi.cmd_buf, 0, size);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_BMI,
|
||||
"bmi LZ stream start: addr: 0x%x)\n",
|
||||
addr);
|
||||
|
||||
offset = 0;
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
|
||||
offset += sizeof(cid);
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
|
||||
offset += sizeof(addr);
|
||||
|
||||
ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to start LZ stream to the device: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath6kl_bmi_fast_download(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
|
||||
{
|
||||
int ret;
|
||||
u32 last_word = 0;
|
||||
u32 last_word_offset = len & ~0x3;
|
||||
u32 unaligned_bytes = len & 0x3;
|
||||
|
||||
ret = ath6kl_bmi_lz_stream_start(ar, addr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (unaligned_bytes) {
|
||||
/* copy the last word into a zero padded buffer */
|
||||
memcpy(&last_word, &buf[last_word_offset], unaligned_bytes);
|
||||
}
|
||||
|
||||
ret = ath6kl_bmi_lz_data(ar, buf, last_word_offset);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (unaligned_bytes)
|
||||
ret = ath6kl_bmi_lz_data(ar, (u8 *)&last_word, 4);
|
||||
|
||||
if (!ret) {
|
||||
/* Close compressed stream and open a new (fake) one.
|
||||
* This serves mainly to flush Target caches. */
|
||||
ret = ath6kl_bmi_lz_stream_start(ar, 0x00);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ath6kl_bmi_init(struct ath6kl *ar)
|
||||
{
|
||||
ar->bmi.cmd_buf = kzalloc(MAX_BMI_CMDBUF_SZ, GFP_ATOMIC);
|
||||
|
||||
if (!ar->bmi.cmd_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ath6kl_bmi_cleanup(struct ath6kl *ar)
|
||||
{
|
||||
kfree(ar->bmi.cmd_buf);
|
||||
ar->bmi.cmd_buf = NULL;
|
||||
}
|
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2011 Atheros Communications 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 BMI_H
|
||||
#define BMI_H
|
||||
|
||||
/*
|
||||
* Bootloader Messaging Interface (BMI)
|
||||
*
|
||||
* BMI is a very simple messaging interface used during initialization
|
||||
* to read memory, write memory, execute code, and to define an
|
||||
* application entry PC.
|
||||
*
|
||||
* It is used to download an application to ATH6KL, to provide
|
||||
* patches to code that is already resident on ATH6KL, and generally
|
||||
* to examine and modify state. The Host has an opportunity to use
|
||||
* BMI only once during bootup. Once the Host issues a BMI_DONE
|
||||
* command, this opportunity ends.
|
||||
*
|
||||
* The Host writes BMI requests to mailbox0, and reads BMI responses
|
||||
* from mailbox0. BMI requests all begin with a command
|
||||
* (see below for specific commands), and are followed by
|
||||
* command-specific data.
|
||||
*
|
||||
* Flow control:
|
||||
* The Host can only issue a command once the Target gives it a
|
||||
* "BMI Command Credit", using ATH6KL Counter #4. As soon as the
|
||||
* Target has completed a command, it issues another BMI Command
|
||||
* Credit (so the Host can issue the next command).
|
||||
*
|
||||
* BMI handles all required Target-side cache flushing.
|
||||
*/
|
||||
|
||||
#define MAX_BMI_CMDBUF_SZ (BMI_DATASZ_MAX + \
|
||||
(sizeof(u32) * 3 /* cmd + addr + len */))
|
||||
|
||||
/* Maximum data size used for BMI transfers */
|
||||
#define BMI_DATASZ_MAX 256
|
||||
|
||||
/* BMI Commands */
|
||||
|
||||
#define BMI_NO_COMMAND 0
|
||||
|
||||
#define BMI_DONE 1
|
||||
/*
|
||||
* Semantics: Host is done using BMI
|
||||
* Request format:
|
||||
* u32 command (BMI_DONE)
|
||||
* Response format: none
|
||||
*/
|
||||
|
||||
#define BMI_READ_MEMORY 2
|
||||
/*
|
||||
* Semantics: Host reads ATH6KL memory
|
||||
* Request format:
|
||||
* u32 command (BMI_READ_MEMORY)
|
||||
* u32 address
|
||||
* u32 length, at most BMI_DATASZ_MAX
|
||||
* Response format:
|
||||
* u8 data[length]
|
||||
*/
|
||||
|
||||
#define BMI_WRITE_MEMORY 3
|
||||
/*
|
||||
* Semantics: Host writes ATH6KL memory
|
||||
* Request format:
|
||||
* u32 command (BMI_WRITE_MEMORY)
|
||||
* u32 address
|
||||
* u32 length, at most BMI_DATASZ_MAX
|
||||
* u8 data[length]
|
||||
* Response format: none
|
||||
*/
|
||||
|
||||
#define BMI_EXECUTE 4
|
||||
/*
|
||||
* Semantics: Causes ATH6KL to execute code
|
||||
* Request format:
|
||||
* u32 command (BMI_EXECUTE)
|
||||
* u32 address
|
||||
* u32 parameter
|
||||
* Response format:
|
||||
* u32 return value
|
||||
*/
|
||||
|
||||
#define BMI_SET_APP_START 5
|
||||
/*
|
||||
* Semantics: Set Target application starting address
|
||||
* Request format:
|
||||
* u32 command (BMI_SET_APP_START)
|
||||
* u32 address
|
||||
* Response format: none
|
||||
*/
|
||||
|
||||
#define BMI_READ_SOC_REGISTER 6
|
||||
/*
|
||||
* Semantics: Read a 32-bit Target SOC register.
|
||||
* Request format:
|
||||
* u32 command (BMI_READ_REGISTER)
|
||||
* u32 address
|
||||
* Response format:
|
||||
* u32 value
|
||||
*/
|
||||
|
||||
#define BMI_WRITE_SOC_REGISTER 7
|
||||
/*
|
||||
* Semantics: Write a 32-bit Target SOC register.
|
||||
* Request format:
|
||||
* u32 command (BMI_WRITE_REGISTER)
|
||||
* u32 address
|
||||
* u32 value
|
||||
*
|
||||
* Response format: none
|
||||
*/
|
||||
|
||||
#define BMI_GET_TARGET_ID 8
|
||||
#define BMI_GET_TARGET_INFO 8
|
||||
/*
|
||||
* Semantics: Fetch the 4-byte Target information
|
||||
* Request format:
|
||||
* u32 command (BMI_GET_TARGET_ID/INFO)
|
||||
* Response format1 (old firmware):
|
||||
* u32 TargetVersionID
|
||||
* Response format2 (newer firmware):
|
||||
* u32 TARGET_VERSION_SENTINAL
|
||||
* struct bmi_target_info;
|
||||
*/
|
||||
|
||||
#define TARGET_VERSION_SENTINAL 0xffffffff
|
||||
#define TARGET_TYPE_AR6003 3
|
||||
|
||||
#define BMI_ROMPATCH_INSTALL 9
|
||||
/*
|
||||
* Semantics: Install a ROM Patch.
|
||||
* Request format:
|
||||
* u32 command (BMI_ROMPATCH_INSTALL)
|
||||
* u32 Target ROM Address
|
||||
* u32 Target RAM Address or Value (depending on Target Type)
|
||||
* u32 Size, in bytes
|
||||
* u32 Activate? 1-->activate;
|
||||
* 0-->install but do not activate
|
||||
* Response format:
|
||||
* u32 PatchID
|
||||
*/
|
||||
|
||||
#define BMI_ROMPATCH_UNINSTALL 10
|
||||
/*
|
||||
* Semantics: Uninstall a previously-installed ROM Patch,
|
||||
* automatically deactivating, if necessary.
|
||||
* Request format:
|
||||
* u32 command (BMI_ROMPATCH_UNINSTALL)
|
||||
* u32 PatchID
|
||||
*
|
||||
* Response format: none
|
||||
*/
|
||||
|
||||
#define BMI_ROMPATCH_ACTIVATE 11
|
||||
/*
|
||||
* Semantics: Activate a list of previously-installed ROM Patches.
|
||||
* Request format:
|
||||
* u32 command (BMI_ROMPATCH_ACTIVATE)
|
||||
* u32 rompatch_count
|
||||
* u32 PatchID[rompatch_count]
|
||||
*
|
||||
* Response format: none
|
||||
*/
|
||||
|
||||
#define BMI_ROMPATCH_DEACTIVATE 12
|
||||
/*
|
||||
* Semantics: Deactivate a list of active ROM Patches.
|
||||
* Request format:
|
||||
* u32 command (BMI_ROMPATCH_DEACTIVATE)
|
||||
* u32 rompatch_count
|
||||
* u32 PatchID[rompatch_count]
|
||||
*
|
||||
* Response format: none
|
||||
*/
|
||||
|
||||
|
||||
#define BMI_LZ_STREAM_START 13
|
||||
/*
|
||||
* Semantics: Begin an LZ-compressed stream of input
|
||||
* which is to be uncompressed by the Target to an
|
||||
* output buffer at address. The output buffer must
|
||||
* be sufficiently large to hold the uncompressed
|
||||
* output from the compressed input stream. This BMI
|
||||
* command should be followed by a series of 1 or more
|
||||
* BMI_LZ_DATA commands.
|
||||
* u32 command (BMI_LZ_STREAM_START)
|
||||
* u32 address
|
||||
* Note: Not supported on all versions of ROM firmware.
|
||||
*/
|
||||
|
||||
#define BMI_LZ_DATA 14
|
||||
/*
|
||||
* Semantics: Host writes ATH6KL memory with LZ-compressed
|
||||
* data which is uncompressed by the Target. This command
|
||||
* must be preceded by a BMI_LZ_STREAM_START command. A series
|
||||
* of BMI_LZ_DATA commands are considered part of a single
|
||||
* input stream until another BMI_LZ_STREAM_START is issued.
|
||||
* Request format:
|
||||
* u32 command (BMI_LZ_DATA)
|
||||
* u32 length (of compressed data),
|
||||
* at most BMI_DATASZ_MAX
|
||||
* u8 CompressedData[length]
|
||||
* Response format: none
|
||||
* Note: Not supported on all versions of ROM firmware.
|
||||
*/
|
||||
|
||||
#define BMI_COMMUNICATION_TIMEOUT 1000 /* in msec */
|
||||
|
||||
struct ath6kl;
|
||||
struct ath6kl_bmi_target_info {
|
||||
__le32 byte_count; /* size of this structure */
|
||||
__le32 version; /* target version id */
|
||||
__le32 type; /* target type */
|
||||
} __packed;
|
||||
|
||||
int ath6kl_bmi_init(struct ath6kl *ar);
|
||||
void ath6kl_bmi_cleanup(struct ath6kl *ar);
|
||||
int ath6kl_bmi_done(struct ath6kl *ar);
|
||||
int ath6kl_bmi_get_target_info(struct ath6kl *ar,
|
||||
struct ath6kl_bmi_target_info *targ_info);
|
||||
int ath6kl_bmi_read(struct ath6kl *ar, u32 addr, u8 *buf, u32 len);
|
||||
int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len);
|
||||
int ath6kl_bmi_execute(struct ath6kl *ar,
|
||||
u32 addr, u32 *param);
|
||||
int ath6kl_bmi_set_app_start(struct ath6kl *ar,
|
||||
u32 addr);
|
||||
int ath6kl_bmi_reg_read(struct ath6kl *ar, u32 addr, u32 *param);
|
||||
int ath6kl_bmi_reg_write(struct ath6kl *ar, u32 addr, u32 param);
|
||||
int ath6kl_bmi_lz_data(struct ath6kl *ar,
|
||||
u8 *buf, u32 len);
|
||||
int ath6kl_bmi_lz_stream_start(struct ath6kl *ar,
|
||||
u32 addr);
|
||||
int ath6kl_bmi_fast_download(struct ath6kl *ar,
|
||||
u32 addr, u8 *buf, u32 len);
|
||||
#endif
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2011 Atheros Communications 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 ATH6KL_CFG80211_H
|
||||
#define ATH6KL_CFG80211_H
|
||||
|
||||
struct wireless_dev *ath6kl_cfg80211_init(struct device *dev);
|
||||
void ath6kl_cfg80211_deinit(struct ath6kl *ar);
|
||||
|
||||
void ath6kl_cfg80211_scan_complete_event(struct ath6kl *ar, int status);
|
||||
|
||||
void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel,
|
||||
u8 *bssid, u16 listen_intvl,
|
||||
u16 beacon_intvl,
|
||||
enum network_type nw_type,
|
||||
u8 beacon_ie_len, u8 assoc_req_len,
|
||||
u8 assoc_resp_len, u8 *assoc_info);
|
||||
|
||||
void ath6kl_cfg80211_disconnect_event(struct ath6kl *ar, u8 reason,
|
||||
u8 *bssid, u8 assoc_resp_len,
|
||||
u8 *assoc_info, u16 proto_reason);
|
||||
|
||||
void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl *ar, u8 keyid,
|
||||
bool ismcast);
|
||||
|
||||
#endif /* ATH6KL_CFG80211_H */
|
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2011 Atheros Communications 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 COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#define ATH6KL_MAX_IE 256
|
||||
|
||||
extern int ath6kl_printk(const char *level, const char *fmt, ...);
|
||||
|
||||
#define A_CACHE_LINE_PAD 128
|
||||
|
||||
/*
|
||||
* Reflects the version of binary interface exposed by ATH6KL target
|
||||
* firmware. Needs to be incremented by 1 for any change in the firmware
|
||||
* that requires upgrade of the driver on the host side for the change to
|
||||
* work correctly
|
||||
*/
|
||||
#define ATH6KL_ABI_VERSION 1
|
||||
|
||||
#define SIGNAL_QUALITY_METRICS_NUM_MAX 2
|
||||
|
||||
enum {
|
||||
SIGNAL_QUALITY_METRICS_SNR = 0,
|
||||
SIGNAL_QUALITY_METRICS_RSSI,
|
||||
SIGNAL_QUALITY_METRICS_ALL,
|
||||
};
|
||||
|
||||
/*
|
||||
* Data Path
|
||||
*/
|
||||
|
||||
#define WMI_MAX_TX_DATA_FRAME_LENGTH \
|
||||
(1500 + sizeof(struct wmi_data_hdr) + \
|
||||
sizeof(struct ethhdr) + \
|
||||
sizeof(struct ath6kl_llc_snap_hdr))
|
||||
|
||||
/* An AMSDU frame */ /* The MAX AMSDU length of AR6003 is 3839 */
|
||||
#define WMI_MAX_AMSDU_RX_DATA_FRAME_LENGTH \
|
||||
(3840 + sizeof(struct wmi_data_hdr) + \
|
||||
sizeof(struct ethhdr) + \
|
||||
sizeof(struct ath6kl_llc_snap_hdr))
|
||||
|
||||
#define EPPING_ALIGNMENT_PAD \
|
||||
(((sizeof(struct htc_frame_hdr) + 3) & (~0x3)) \
|
||||
- sizeof(struct htc_frame_hdr))
|
||||
|
||||
struct ath6kl_llc_snap_hdr {
|
||||
u8 dsap;
|
||||
u8 ssap;
|
||||
u8 cntl;
|
||||
u8 org_code[3];
|
||||
__be16 eth_type;
|
||||
} __packed;
|
||||
|
||||
enum crypto_type {
|
||||
NONE_CRYPT = 0x01,
|
||||
WEP_CRYPT = 0x02,
|
||||
TKIP_CRYPT = 0x04,
|
||||
AES_CRYPT = 0x08,
|
||||
};
|
||||
|
||||
#define ATH6KL_NODE_HASHSIZE 32
|
||||
/* simple hash is enough for variation of macaddr */
|
||||
#define ATH6KL_NODE_HASH(addr) \
|
||||
(((const u8 *)(addr))[ETH_ALEN - 1] % \
|
||||
ATH6KL_NODE_HASHSIZE)
|
||||
|
||||
/*
|
||||
* Table of ath6kl_node instances. Each ieee80211com
|
||||
* has at least one for holding the scan candidates.
|
||||
* When operating as an access point or in ibss mode there
|
||||
* is a second table for associated stations or neighbors.
|
||||
*/
|
||||
struct ath6kl_node_table {
|
||||
spinlock_t nt_nodelock; /* on node table */
|
||||
struct bss *nt_node_first; /* information of all nodes */
|
||||
struct bss *nt_node_last; /* information of all nodes */
|
||||
struct bss *nt_hash[ATH6KL_NODE_HASHSIZE];
|
||||
const char *nt_name; /* for debugging */
|
||||
u32 nt_node_age; /* node aging time */
|
||||
};
|
||||
|
||||
#define WLAN_NODE_INACT_TIMEOUT_MSEC 120000
|
||||
#define WLAN_NODE_INACT_CNT 4
|
||||
|
||||
struct ath6kl_common_ie {
|
||||
u16 ie_chan;
|
||||
u8 *ie_tstamp;
|
||||
u8 *ie_ssid;
|
||||
u8 *ie_rates;
|
||||
u8 *ie_xrates;
|
||||
u8 *ie_country;
|
||||
u8 *ie_wpa;
|
||||
u8 *ie_rsn;
|
||||
u8 *ie_wmm;
|
||||
u8 *ie_ath;
|
||||
u16 ie_capInfo;
|
||||
u16 ie_beaconInt;
|
||||
u8 *ie_tim;
|
||||
u8 *ie_chswitch;
|
||||
u8 ie_erp;
|
||||
u8 *ie_wsc;
|
||||
u8 *ie_htcap;
|
||||
u8 *ie_htop;
|
||||
};
|
||||
|
||||
struct bss {
|
||||
u8 ni_macaddr[ETH_ALEN];
|
||||
u8 ni_snr;
|
||||
s16 ni_rssi;
|
||||
struct bss *ni_list_next;
|
||||
struct bss *ni_list_prev;
|
||||
struct bss *ni_hash_next;
|
||||
struct bss *ni_hash_prev;
|
||||
struct ath6kl_common_ie ni_cie;
|
||||
u8 *ni_buf;
|
||||
u16 ni_framelen;
|
||||
struct ath6kl_node_table *ni_table;
|
||||
u32 ni_refcnt;
|
||||
|
||||
u32 ni_tstamp;
|
||||
u32 ni_actcnt;
|
||||
};
|
||||
|
||||
struct htc_endpoint_credit_dist;
|
||||
struct ath6kl;
|
||||
enum htc_credit_dist_reason;
|
||||
struct htc_credit_state_info;
|
||||
|
||||
struct bss *wlan_node_alloc(int wh_size);
|
||||
void wlan_node_free(struct bss *ni);
|
||||
void wlan_setup_node(struct ath6kl_node_table *nt, struct bss *ni,
|
||||
const u8 *mac_addr);
|
||||
struct bss *wlan_find_node(struct ath6kl_node_table *nt,
|
||||
const u8 *mac_addr);
|
||||
void wlan_node_reclaim(struct ath6kl_node_table *nt, struct bss *ni);
|
||||
void wlan_free_allnodes(struct ath6kl_node_table *nt);
|
||||
void wlan_iterate_nodes(struct ath6kl_node_table *nt, void *arg);
|
||||
|
||||
void wlan_node_table_init(struct ath6kl_node_table *nt);
|
||||
void wlan_node_table_cleanup(struct ath6kl_node_table *nt);
|
||||
|
||||
void wlan_refresh_inactive_nodes(struct ath6kl *ar);
|
||||
|
||||
struct bss *wlan_find_ssid_node(struct ath6kl_node_table *nt, u8 *ssid,
|
||||
u32 ssid_len, bool is_wpa2, bool match_ssid);
|
||||
|
||||
void wlan_node_return(struct ath6kl_node_table *nt, struct bss *ni);
|
||||
|
||||
int ath6k_setup_credit_dist(void *htc_handle,
|
||||
struct htc_credit_state_info *cred_info);
|
||||
void ath6k_credit_distribute(struct htc_credit_state_info *cred_inf,
|
||||
struct list_head *epdist_list,
|
||||
enum htc_credit_dist_reason reason);
|
||||
void ath6k_credit_init(struct htc_credit_state_info *cred_inf,
|
||||
struct list_head *ep_list,
|
||||
int tot_credits);
|
||||
void ath6k_seek_credits(struct htc_credit_state_info *cred_inf,
|
||||
struct htc_endpoint_credit_dist *ep_dist);
|
||||
struct ath6kl *ath6kl_core_alloc(struct device *sdev);
|
||||
int ath6kl_core_init(struct ath6kl *ar);
|
||||
int ath6kl_unavail_ev(struct ath6kl *ar);
|
||||
struct sk_buff *ath6kl_buf_alloc(int size);
|
||||
#endif /* COMMON_H */
|
|
@ -0,0 +1,544 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2011 Atheros Communications 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 CORE_H
|
||||
#define CORE_H
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/sched.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include "htc.h"
|
||||
#include "wmi.h"
|
||||
#include "bmi.h"
|
||||
|
||||
#define MAX_ATH6KL 1
|
||||
#define ATH6KL_MAX_RX_BUFFERS 16
|
||||
#define ATH6KL_BUFFER_SIZE 1664
|
||||
#define ATH6KL_MAX_AMSDU_RX_BUFFERS 4
|
||||
#define ATH6KL_AMSDU_REFILL_THRESHOLD 3
|
||||
#define ATH6KL_AMSDU_BUFFER_SIZE (WMI_MAX_AMSDU_RX_DATA_FRAME_LENGTH + 128)
|
||||
#define MAX_MSDU_SUBFRAME_PAYLOAD_LEN 1508
|
||||
#define MIN_MSDU_SUBFRAME_PAYLOAD_LEN 46
|
||||
|
||||
#define USER_SAVEDKEYS_STAT_INIT 0
|
||||
#define USER_SAVEDKEYS_STAT_RUN 1
|
||||
|
||||
#define ATH6KL_TX_TIMEOUT 10
|
||||
#define ATH6KL_MAX_ENDPOINTS 4
|
||||
#define MAX_NODE_NUM 15
|
||||
|
||||
/* MAX_HI_COOKIE_NUM are reserved for high priority traffic */
|
||||
#define MAX_DEF_COOKIE_NUM 180
|
||||
#define MAX_HI_COOKIE_NUM 18 /* 10% of MAX_COOKIE_NUM */
|
||||
#define MAX_COOKIE_NUM (MAX_DEF_COOKIE_NUM + MAX_HI_COOKIE_NUM)
|
||||
|
||||
#define MAX_DEFAULT_SEND_QUEUE_DEPTH (MAX_DEF_COOKIE_NUM / WMM_NUM_AC)
|
||||
|
||||
#define DISCON_TIMER_INTVAL 10000 /* in msec */
|
||||
#define A_DEFAULT_LISTEN_INTERVAL 100
|
||||
#define A_MAX_WOW_LISTEN_INTERVAL 1000
|
||||
|
||||
/* AR6003 1.0 definitions */
|
||||
#define AR6003_REV1_VERSION 0x300002ba
|
||||
|
||||
/* AR6003 2.0 definitions */
|
||||
#define AR6003_REV2_VERSION 0x30000384
|
||||
#define AR6003_REV2_PATCH_DOWNLOAD_ADDRESS 0x57e910
|
||||
#define AR6003_REV2_OTP_FILE "ath6k/AR6003/hw2.0/otp.bin.z77"
|
||||
#define AR6003_REV2_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athwlan.bin.z77"
|
||||
#define AR6003_REV2_PATCH_FILE "ath6k/AR6003/hw2.0/data.patch.bin"
|
||||
#define AR6003_REV2_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.bin"
|
||||
#define AR6003_REV2_DEFAULT_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.SD31.bin"
|
||||
|
||||
/* AR6003 3.0 definitions */
|
||||
#define AR6003_REV3_VERSION 0x30000582
|
||||
#define AR6003_REV3_OTP_FILE "ath6k/AR6003/hw2.1.1/otp.bin"
|
||||
#define AR6003_REV3_FIRMWARE_FILE "ath6k/AR6003/hw2.1.1/athwlan.bin"
|
||||
#define AR6003_REV3_PATCH_FILE "ath6k/AR6003/hw2.1.1/data.patch.bin"
|
||||
#define AR6003_REV3_BOARD_DATA_FILE "ath6k/AR6003/hw2.1.1/bdata.bin"
|
||||
#define AR6003_REV3_DEFAULT_BOARD_DATA_FILE \
|
||||
"ath6k/AR6003/hw2.1.1/bdata.SD31.bin"
|
||||
|
||||
/* Per STA data, used in AP mode */
|
||||
#define STA_PS_AWAKE BIT(0)
|
||||
#define STA_PS_SLEEP BIT(1)
|
||||
#define STA_PS_POLLED BIT(2)
|
||||
|
||||
/* HTC TX packet tagging definitions */
|
||||
#define ATH6KL_CONTROL_PKT_TAG HTC_TX_PACKET_TAG_USER_DEFINED
|
||||
#define ATH6KL_DATA_PKT_TAG (ATH6KL_CONTROL_PKT_TAG + 1)
|
||||
|
||||
#define AR6003_CUST_DATA_SIZE 16
|
||||
|
||||
#define AGGR_WIN_IDX(x, y) ((x) % (y))
|
||||
#define AGGR_INCR_IDX(x, y) AGGR_WIN_IDX(((x) + 1), (y))
|
||||
#define AGGR_DCRM_IDX(x, y) AGGR_WIN_IDX(((x) - 1), (y))
|
||||
#define ATH6KL_MAX_SEQ_NO 0xFFF
|
||||
#define ATH6KL_NEXT_SEQ_NO(x) (((x) + 1) & ATH6KL_MAX_SEQ_NO)
|
||||
|
||||
#define NUM_OF_TIDS 8
|
||||
#define AGGR_SZ_DEFAULT 8
|
||||
|
||||
#define AGGR_WIN_SZ_MIN 2
|
||||
#define AGGR_WIN_SZ_MAX 8
|
||||
|
||||
#define TID_WINDOW_SZ(_x) ((_x) << 1)
|
||||
|
||||
#define AGGR_NUM_OF_FREE_NETBUFS 16
|
||||
|
||||
#define AGGR_RX_TIMEOUT 400 /* in ms */
|
||||
|
||||
#define WMI_TIMEOUT (2 * HZ)
|
||||
|
||||
#define MBOX_YIELD_LIMIT 99
|
||||
|
||||
/* configuration lags */
|
||||
/*
|
||||
* ATH6KL_CONF_IGNORE_ERP_BARKER: Ignore the barker premable in
|
||||
* ERP IE of beacon to determine the short premable support when
|
||||
* sending (Re)Assoc req.
|
||||
* ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN: Don't send the power
|
||||
* module state transition failure events which happen during
|
||||
* scan, to the host.
|
||||
*/
|
||||
#define ATH6KL_CONF_IGNORE_ERP_BARKER BIT(0)
|
||||
#define ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN BIT(1)
|
||||
#define ATH6KL_CONF_ENABLE_11N BIT(2)
|
||||
#define ATH6KL_CONF_ENABLE_TX_BURST BIT(3)
|
||||
|
||||
enum wlan_low_pwr_state {
|
||||
WLAN_POWER_STATE_ON,
|
||||
WLAN_POWER_STATE_CUT_PWR,
|
||||
WLAN_POWER_STATE_DEEP_SLEEP,
|
||||
WLAN_POWER_STATE_WOW
|
||||
};
|
||||
|
||||
enum sme_state {
|
||||
SME_DISCONNECTED,
|
||||
SME_CONNECTING,
|
||||
SME_CONNECTED
|
||||
};
|
||||
|
||||
struct skb_hold_q {
|
||||
struct sk_buff *skb;
|
||||
bool is_amsdu;
|
||||
u16 seq_no;
|
||||
};
|
||||
|
||||
struct rxtid {
|
||||
bool aggr;
|
||||
bool progress;
|
||||
bool timer_mon;
|
||||
u16 win_sz;
|
||||
u16 seq_next;
|
||||
u32 hold_q_sz;
|
||||
struct skb_hold_q *hold_q;
|
||||
struct sk_buff_head q;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
struct rxtid_stats {
|
||||
u32 num_into_aggr;
|
||||
u32 num_dups;
|
||||
u32 num_oow;
|
||||
u32 num_mpdu;
|
||||
u32 num_amsdu;
|
||||
u32 num_delivered;
|
||||
u32 num_timeouts;
|
||||
u32 num_hole;
|
||||
u32 num_bar;
|
||||
};
|
||||
|
||||
struct aggr_info {
|
||||
u8 aggr_sz;
|
||||
u8 timer_scheduled;
|
||||
struct timer_list timer;
|
||||
struct net_device *dev;
|
||||
struct rxtid rx_tid[NUM_OF_TIDS];
|
||||
struct sk_buff_head free_q;
|
||||
struct rxtid_stats stat[NUM_OF_TIDS];
|
||||
};
|
||||
|
||||
struct ath6kl_wep_key {
|
||||
u8 key_index;
|
||||
u8 key_len;
|
||||
u8 key[64];
|
||||
};
|
||||
|
||||
#define ATH6KL_KEY_SEQ_LEN 8
|
||||
|
||||
struct ath6kl_key {
|
||||
u8 key[WLAN_MAX_KEY_LEN];
|
||||
u8 key_len;
|
||||
u8 seq[ATH6KL_KEY_SEQ_LEN];
|
||||
u8 seq_len;
|
||||
u32 cipher;
|
||||
};
|
||||
|
||||
struct ath6kl_node_mapping {
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
u8 ep_id;
|
||||
u8 tx_pend;
|
||||
};
|
||||
|
||||
struct ath6kl_cookie {
|
||||
struct sk_buff *skb;
|
||||
u32 map_no;
|
||||
struct htc_packet htc_pkt;
|
||||
struct ath6kl_cookie *arc_list_next;
|
||||
};
|
||||
|
||||
struct ath6kl_sta {
|
||||
u16 sta_flags;
|
||||
u8 mac[ETH_ALEN];
|
||||
u8 aid;
|
||||
u8 keymgmt;
|
||||
u8 ucipher;
|
||||
u8 auth;
|
||||
u8 wpa_ie[ATH6KL_MAX_IE];
|
||||
struct sk_buff_head psq;
|
||||
spinlock_t psq_lock;
|
||||
};
|
||||
|
||||
struct ath6kl_version {
|
||||
u32 target_ver;
|
||||
u32 wlan_ver;
|
||||
u32 abi_ver;
|
||||
};
|
||||
|
||||
struct ath6kl_bmi {
|
||||
u32 cmd_credits;
|
||||
bool done_sent;
|
||||
u8 *cmd_buf;
|
||||
};
|
||||
|
||||
struct target_stats {
|
||||
u64 tx_pkt;
|
||||
u64 tx_byte;
|
||||
u64 tx_ucast_pkt;
|
||||
u64 tx_ucast_byte;
|
||||
u64 tx_mcast_pkt;
|
||||
u64 tx_mcast_byte;
|
||||
u64 tx_bcast_pkt;
|
||||
u64 tx_bcast_byte;
|
||||
u64 tx_rts_success_cnt;
|
||||
u64 tx_pkt_per_ac[4];
|
||||
|
||||
u64 tx_err;
|
||||
u64 tx_fail_cnt;
|
||||
u64 tx_retry_cnt;
|
||||
u64 tx_mult_retry_cnt;
|
||||
u64 tx_rts_fail_cnt;
|
||||
|
||||
u64 rx_pkt;
|
||||
u64 rx_byte;
|
||||
u64 rx_ucast_pkt;
|
||||
u64 rx_ucast_byte;
|
||||
u64 rx_mcast_pkt;
|
||||
u64 rx_mcast_byte;
|
||||
u64 rx_bcast_pkt;
|
||||
u64 rx_bcast_byte;
|
||||
u64 rx_frgment_pkt;
|
||||
|
||||
u64 rx_err;
|
||||
u64 rx_crc_err;
|
||||
u64 rx_key_cache_miss;
|
||||
u64 rx_decrypt_err;
|
||||
u64 rx_dupl_frame;
|
||||
|
||||
u64 tkip_local_mic_fail;
|
||||
u64 tkip_cnter_measures_invoked;
|
||||
u64 tkip_replays;
|
||||
u64 tkip_fmt_err;
|
||||
u64 ccmp_fmt_err;
|
||||
u64 ccmp_replays;
|
||||
|
||||
u64 pwr_save_fail_cnt;
|
||||
|
||||
u64 cs_bmiss_cnt;
|
||||
u64 cs_low_rssi_cnt;
|
||||
u64 cs_connect_cnt;
|
||||
u64 cs_discon_cnt;
|
||||
|
||||
s32 tx_ucast_rate;
|
||||
s32 rx_ucast_rate;
|
||||
|
||||
u32 lq_val;
|
||||
|
||||
u32 wow_pkt_dropped;
|
||||
u16 wow_evt_discarded;
|
||||
|
||||
s16 noise_floor_calib;
|
||||
s16 cs_rssi;
|
||||
s16 cs_ave_beacon_rssi;
|
||||
u8 cs_ave_beacon_snr;
|
||||
u8 cs_last_roam_msec;
|
||||
u8 cs_snr;
|
||||
|
||||
u8 wow_host_pkt_wakeups;
|
||||
u8 wow_host_evt_wakeups;
|
||||
|
||||
u32 arp_received;
|
||||
u32 arp_matched;
|
||||
u32 arp_replied;
|
||||
};
|
||||
|
||||
struct ath6kl_mbox_info {
|
||||
u32 htc_addr;
|
||||
u32 htc_ext_addr;
|
||||
u32 htc_ext_sz;
|
||||
|
||||
u32 block_size;
|
||||
|
||||
u32 gmbox_addr;
|
||||
|
||||
u32 gmbox_sz;
|
||||
};
|
||||
|
||||
/*
|
||||
* 802.11i defines an extended IV for use with non-WEP ciphers.
|
||||
* When the EXTIV bit is set in the key id byte an additional
|
||||
* 4 bytes immediately follow the IV for TKIP. For CCMP the
|
||||
* EXTIV bit is likewise set but the 8 bytes represent the
|
||||
* CCMP header rather than IV+extended-IV.
|
||||
*/
|
||||
|
||||
#define ATH6KL_KEYBUF_SIZE 16
|
||||
#define ATH6KL_MICBUF_SIZE (8+8) /* space for both tx and rx */
|
||||
|
||||
#define ATH6KL_KEY_XMIT 0x01
|
||||
#define ATH6KL_KEY_RECV 0x02
|
||||
#define ATH6KL_KEY_DEFAULT 0x80 /* default xmit key */
|
||||
|
||||
/*
|
||||
* WPA/RSN get/set key request. Specify the key/cipher
|
||||
* type and whether the key is to be used for sending and/or
|
||||
* receiving. The key index should be set only when working
|
||||
* with global keys (use IEEE80211_KEYIX_NONE for ``no index'').
|
||||
* Otherwise a unicast/pairwise key is specified by the bssid
|
||||
* (on a station) or mac address (on an ap). They key length
|
||||
* must include any MIC key data; otherwise it should be no
|
||||
* more than ATH6KL_KEYBUF_SIZE.
|
||||
*/
|
||||
struct ath6kl_req_key {
|
||||
u8 ik_type; /* key/cipher type */
|
||||
u8 ik_pad;
|
||||
u16 ik_keyix; /* key index */
|
||||
u8 ik_keylen; /* key length in bytes */
|
||||
u8 ik_flags;
|
||||
u8 ik_macaddr[ETH_ALEN];
|
||||
u64 ik_keyrsc; /* key receive sequence counter */
|
||||
u64 ik_keytsc; /* key transmit sequence counter */
|
||||
u8 ik_keydata[ATH6KL_KEYBUF_SIZE + ATH6KL_MICBUF_SIZE];
|
||||
};
|
||||
|
||||
/* Flag info */
|
||||
#define WMI_ENABLED 0
|
||||
#define WMI_READY 1
|
||||
#define CONNECTED 2
|
||||
#define STATS_UPDATE_PEND 3
|
||||
#define CONNECT_PEND 4
|
||||
#define WMM_ENABLED 5
|
||||
#define NETQ_STOPPED 6
|
||||
#define WMI_CTRL_EP_FULL 7
|
||||
#define DTIM_EXPIRED 8
|
||||
#define DESTROY_IN_PROGRESS 9
|
||||
#define NETDEV_REGISTERED 10
|
||||
#define SKIP_SCAN 11
|
||||
#define WLAN_ENABLED 12
|
||||
|
||||
struct ath6kl {
|
||||
struct device *dev;
|
||||
struct net_device *net_dev;
|
||||
struct ath6kl_bmi bmi;
|
||||
const struct ath6kl_hif_ops *hif_ops;
|
||||
struct wmi *wmi;
|
||||
int tx_pending[ENDPOINT_MAX];
|
||||
int total_tx_data_pend;
|
||||
struct htc_target *htc_target;
|
||||
void *hif_priv;
|
||||
spinlock_t lock;
|
||||
struct semaphore sem;
|
||||
int ssid_len;
|
||||
u8 ssid[IEEE80211_MAX_SSID_LEN];
|
||||
u8 next_mode;
|
||||
u8 nw_type;
|
||||
u8 dot11_auth_mode;
|
||||
u8 auth_mode;
|
||||
u8 prwise_crypto;
|
||||
u8 prwise_crypto_len;
|
||||
u8 grp_crypto;
|
||||
u8 grp_crpto_len;
|
||||
u8 def_txkey_index;
|
||||
struct ath6kl_wep_key wep_key_list[WMI_MAX_KEY_INDEX + 1];
|
||||
u8 bssid[ETH_ALEN];
|
||||
u8 req_bssid[ETH_ALEN];
|
||||
u16 ch_hint;
|
||||
u16 bss_ch;
|
||||
u16 listen_intvl_b;
|
||||
u16 listen_intvl_t;
|
||||
struct ath6kl_version version;
|
||||
u32 target_type;
|
||||
u8 tx_pwr;
|
||||
struct net_device_stats net_stats;
|
||||
struct target_stats target_stats;
|
||||
struct ath6kl_node_mapping node_map[MAX_NODE_NUM];
|
||||
u8 ibss_ps_enable;
|
||||
u8 node_num;
|
||||
u8 next_ep_id;
|
||||
struct ath6kl_cookie *cookie_list;
|
||||
u32 cookie_count;
|
||||
enum htc_endpoint_id ac2ep_map[WMM_NUM_AC];
|
||||
bool ac_stream_active[WMM_NUM_AC];
|
||||
u8 ac_stream_pri_map[WMM_NUM_AC];
|
||||
u8 hiac_stream_active_pri;
|
||||
u8 ep2ac_map[ENDPOINT_MAX];
|
||||
enum htc_endpoint_id ctrl_ep;
|
||||
struct htc_credit_state_info credit_state_info;
|
||||
u32 connect_ctrl_flags;
|
||||
u32 user_key_ctrl;
|
||||
u8 usr_bss_filter;
|
||||
struct ath6kl_sta sta_list[AP_MAX_NUM_STA];
|
||||
u8 sta_list_index;
|
||||
struct ath6kl_req_key ap_mode_bkey;
|
||||
struct sk_buff_head mcastpsq;
|
||||
spinlock_t mcastpsq_lock;
|
||||
u8 intra_bss;
|
||||
struct aggr_info *aggr_cntxt;
|
||||
struct wmi_ap_mode_stat ap_stats;
|
||||
u8 ap_country_code[3];
|
||||
struct list_head amsdu_rx_buffer_queue;
|
||||
struct timer_list disconnect_timer;
|
||||
u8 rx_meta_ver;
|
||||
struct wireless_dev *wdev;
|
||||
struct cfg80211_scan_request *scan_req;
|
||||
struct ath6kl_key keys[WMI_MAX_KEY_INDEX + 1];
|
||||
enum sme_state sme_state;
|
||||
enum wlan_low_pwr_state wlan_pwr_state;
|
||||
struct wmi_scan_params_cmd sc_params;
|
||||
#define AR_MCAST_FILTER_MAC_ADDR_SIZE 4
|
||||
u8 auto_auth_stage;
|
||||
|
||||
u16 conf_flags;
|
||||
wait_queue_head_t event_wq;
|
||||
struct ath6kl_mbox_info mbox_info;
|
||||
|
||||
struct ath6kl_cookie cookie_mem[MAX_COOKIE_NUM];
|
||||
int reconnect_flag;
|
||||
unsigned long flag;
|
||||
|
||||
u8 *fw_board;
|
||||
size_t fw_board_len;
|
||||
|
||||
u8 *fw_otp;
|
||||
size_t fw_otp_len;
|
||||
|
||||
u8 *fw;
|
||||
size_t fw_len;
|
||||
|
||||
u8 *fw_patch;
|
||||
size_t fw_patch_len;
|
||||
|
||||
struct workqueue_struct *ath6kl_wq;
|
||||
|
||||
struct ath6kl_node_table scan_table;
|
||||
};
|
||||
|
||||
static inline void *ath6kl_priv(struct net_device *dev)
|
||||
{
|
||||
return wdev_priv(dev->ieee80211_ptr);
|
||||
}
|
||||
|
||||
static inline void ath6kl_deposit_credit_to_ep(struct htc_credit_state_info
|
||||
*cred_info,
|
||||
struct htc_endpoint_credit_dist
|
||||
*ep_dist, int credits)
|
||||
{
|
||||
ep_dist->credits += credits;
|
||||
ep_dist->cred_assngd += credits;
|
||||
cred_info->cur_free_credits -= credits;
|
||||
}
|
||||
|
||||
void ath6kl_destroy(struct net_device *dev, unsigned int unregister);
|
||||
int ath6kl_configure_target(struct ath6kl *ar);
|
||||
void ath6kl_detect_error(unsigned long ptr);
|
||||
void disconnect_timer_handler(unsigned long ptr);
|
||||
void init_netdev(struct net_device *dev);
|
||||
void ath6kl_cookie_init(struct ath6kl *ar);
|
||||
void ath6kl_cookie_cleanup(struct ath6kl *ar);
|
||||
void ath6kl_rx(struct htc_target *target, struct htc_packet *packet);
|
||||
void ath6kl_tx_complete(void *context, struct list_head *packet_queue);
|
||||
enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
|
||||
struct htc_packet *packet);
|
||||
void ath6kl_stop_txrx(struct ath6kl *ar);
|
||||
void ath6kl_cleanup_amsdu_rxbufs(struct ath6kl *ar);
|
||||
int ath6kl_access_datadiag(struct ath6kl *ar, u32 address,
|
||||
u8 *data, u32 length, bool read);
|
||||
int ath6kl_read_reg_diag(struct ath6kl *ar, u32 *address, u32 *data);
|
||||
void ath6kl_init_profile_info(struct ath6kl *ar);
|
||||
void ath6kl_tx_data_cleanup(struct ath6kl *ar);
|
||||
void ath6kl_stop_endpoint(struct net_device *dev, bool keep_profile,
|
||||
bool get_dbglogs);
|
||||
|
||||
struct ath6kl_cookie *ath6kl_alloc_cookie(struct ath6kl *ar);
|
||||
void ath6kl_free_cookie(struct ath6kl *ar, struct ath6kl_cookie *cookie);
|
||||
int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev);
|
||||
|
||||
struct aggr_info *aggr_init(struct net_device *dev);
|
||||
void ath6kl_rx_refill(struct htc_target *target,
|
||||
enum htc_endpoint_id endpoint);
|
||||
void ath6kl_refill_amsdu_rxbufs(struct ath6kl *ar, int count);
|
||||
struct htc_packet *ath6kl_alloc_amsdu_rxbuf(struct htc_target *target,
|
||||
enum htc_endpoint_id endpoint,
|
||||
int len);
|
||||
void aggr_module_destroy(struct aggr_info *aggr_info);
|
||||
void aggr_reset_state(struct aggr_info *aggr_info);
|
||||
|
||||
struct ath6kl_sta *ath6kl_find_sta(struct ath6kl *ar, u8 * node_addr);
|
||||
struct ath6kl_sta *ath6kl_find_sta_by_aid(struct ath6kl *ar, u8 aid);
|
||||
|
||||
void ath6kl_ready_event(void *devt, u8 * datap, u32 sw_ver, u32 abi_ver);
|
||||
int ath6kl_control_tx(void *devt, struct sk_buff *skb,
|
||||
enum htc_endpoint_id eid);
|
||||
void ath6kl_connect_event(struct ath6kl *ar, u16 channel,
|
||||
u8 *bssid, u16 listen_int,
|
||||
u16 beacon_int, enum network_type net_type,
|
||||
u8 beacon_ie_len, u8 assoc_req_len,
|
||||
u8 assoc_resp_len, u8 *assoc_info);
|
||||
void ath6kl_disconnect_event(struct ath6kl *ar, u8 reason,
|
||||
u8 *bssid, u8 assoc_resp_len,
|
||||
u8 *assoc_info, u16 prot_reason_status);
|
||||
void ath6kl_tkip_micerr_event(struct ath6kl *ar, u8 keyid, bool ismcast);
|
||||
void ath6kl_txpwr_rx_evt(void *devt, u8 tx_pwr);
|
||||
void ath6kl_scan_complete_evt(struct ath6kl *ar, int status);
|
||||
void ath6kl_tgt_stats_event(struct ath6kl *ar, u8 *ptr, u32 len);
|
||||
void ath6kl_indicate_tx_activity(void *devt, u8 traffic_class, bool active);
|
||||
enum htc_endpoint_id ath6kl_ac2_endpoint_id(void *devt, u8 ac);
|
||||
|
||||
void ath6kl_pspoll_event(struct ath6kl *ar, u8 aid);
|
||||
|
||||
void ath6kl_dtimexpiry_event(struct ath6kl *ar);
|
||||
void ath6kl_disconnect(struct ath6kl *ar);
|
||||
void aggr_recv_delba_req_evt(struct ath6kl *ar, u8 tid);
|
||||
void aggr_recv_addba_req_evt(struct ath6kl *ar, u8 tid, u16 seq_no,
|
||||
u8 win_sz);
|
||||
void ath6kl_wakeup_event(void *dev);
|
||||
void ath6kl_target_failure(struct ath6kl *ar);
|
||||
|
||||
void ath6kl_cfg80211_scan_node(struct wiphy *wiphy, struct bss *ni);
|
||||
#endif /* CORE_H */
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2011 Atheros Communications 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 "core.h"
|
||||
#include "debug.h"
|
||||
|
||||
int ath6kl_printk(const char *level, const char *fmt, ...)
|
||||
{
|
||||
struct va_format vaf;
|
||||
va_list args;
|
||||
int rtn;
|
||||
|
||||
va_start(args, fmt);
|
||||
|
||||
vaf.fmt = fmt;
|
||||
vaf.va = &args;
|
||||
|
||||
rtn = printk("%sath6kl: %pV", level, &vaf);
|
||||
|
||||
va_end(args);
|
||||
|
||||
return rtn;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ATH6KL_DEBUG
|
||||
void ath6kl_dump_registers(struct ath6kl_device *dev,
|
||||
struct ath6kl_irq_proc_registers *irq_proc_reg,
|
||||
struct ath6kl_irq_enable_reg *irq_enable_reg)
|
||||
{
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY, ("<------- Register Table -------->\n"));
|
||||
|
||||
if (irq_proc_reg != NULL) {
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"Host Int status: 0x%x\n",
|
||||
irq_proc_reg->host_int_status);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"CPU Int status: 0x%x\n",
|
||||
irq_proc_reg->cpu_int_status);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"Error Int status: 0x%x\n",
|
||||
irq_proc_reg->error_int_status);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"Counter Int status: 0x%x\n",
|
||||
irq_proc_reg->counter_int_status);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"Mbox Frame: 0x%x\n",
|
||||
irq_proc_reg->mbox_frame);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"Rx Lookahead Valid: 0x%x\n",
|
||||
irq_proc_reg->rx_lkahd_valid);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"Rx Lookahead 0: 0x%x\n",
|
||||
irq_proc_reg->rx_lkahd[0]);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"Rx Lookahead 1: 0x%x\n",
|
||||
irq_proc_reg->rx_lkahd[1]);
|
||||
|
||||
if (dev->ar->mbox_info.gmbox_addr != 0) {
|
||||
/*
|
||||
* If the target supports GMBOX hardware, dump some
|
||||
* additional state.
|
||||
*/
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"GMBOX Host Int status 2: 0x%x\n",
|
||||
irq_proc_reg->host_int_status2);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"GMBOX RX Avail: 0x%x\n",
|
||||
irq_proc_reg->gmbox_rx_avail);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"GMBOX lookahead alias 0: 0x%x\n",
|
||||
irq_proc_reg->rx_gmbox_lkahd_alias[0]);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"GMBOX lookahead alias 1: 0x%x\n",
|
||||
irq_proc_reg->rx_gmbox_lkahd_alias[1]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (irq_enable_reg != NULL) {
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"Int status Enable: 0x%x\n",
|
||||
irq_enable_reg->int_status_en);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY, "Counter Int status Enable: 0x%x\n",
|
||||
irq_enable_reg->cntr_int_status_en);
|
||||
}
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY, "<------------------------------->\n");
|
||||
}
|
||||
|
||||
static void dump_cred_dist(struct htc_endpoint_credit_dist *ep_dist)
|
||||
{
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"--- endpoint: %d svc_id: 0x%X ---\n",
|
||||
ep_dist->endpoint, ep_dist->svc_id);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY, " dist_flags : 0x%X\n",
|
||||
ep_dist->dist_flags);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY, " cred_norm : %d\n",
|
||||
ep_dist->cred_norm);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY, " cred_min : %d\n",
|
||||
ep_dist->cred_min);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY, " credits : %d\n",
|
||||
ep_dist->credits);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY, " cred_assngd : %d\n",
|
||||
ep_dist->cred_assngd);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY, " seek_cred : %d\n",
|
||||
ep_dist->seek_cred);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY, " cred_sz : %d\n",
|
||||
ep_dist->cred_sz);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY, " cred_per_msg : %d\n",
|
||||
ep_dist->cred_per_msg);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY, " cred_to_dist : %d\n",
|
||||
ep_dist->cred_to_dist);
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY, " txq_depth : %d\n",
|
||||
get_queue_depth(&((struct htc_endpoint *)
|
||||
ep_dist->htc_rsvd)->txq));
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"----------------------------------\n");
|
||||
}
|
||||
|
||||
void dump_cred_dist_stats(struct htc_target *target)
|
||||
{
|
||||
struct htc_endpoint_credit_dist *ep_list;
|
||||
|
||||
if (!AR_DBG_LVL_CHECK(ATH6KL_DBG_TRC))
|
||||
return;
|
||||
|
||||
list_for_each_entry(ep_list, &target->cred_dist_list, list)
|
||||
dump_cred_dist(ep_list);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "ctxt:%p dist:%p\n",
|
||||
target->cred_dist_cntxt, NULL);
|
||||
ath6kl_dbg(ATH6KL_DBG_TRC, "credit distribution, total : %d, free : %d\n",
|
||||
target->cred_dist_cntxt->total_avail_credits,
|
||||
target->cred_dist_cntxt->cur_free_credits);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* Copyright (c) 2011 Atheros Communications 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 DEBUG_H
|
||||
#define DEBUG_H
|
||||
|
||||
#include "htc_hif.h"
|
||||
|
||||
enum ATH6K_DEBUG_MASK {
|
||||
ATH6KL_DBG_WLAN_CONNECT = BIT(0), /* wlan connect */
|
||||
ATH6KL_DBG_WLAN_SCAN = BIT(1), /* wlan scan */
|
||||
ATH6KL_DBG_WLAN_TX = BIT(2), /* wlan tx */
|
||||
ATH6KL_DBG_WLAN_RX = BIT(3), /* wlan rx */
|
||||
ATH6KL_DBG_BMI = BIT(4), /* bmi tracing */
|
||||
ATH6KL_DBG_HTC_SEND = BIT(5), /* htc send */
|
||||
ATH6KL_DBG_HTC_RECV = BIT(6), /* htc recv */
|
||||
ATH6KL_DBG_IRQ = BIT(7), /* interrupt processing */
|
||||
ATH6KL_DBG_PM = BIT(8), /* power management */
|
||||
ATH6KL_DBG_WLAN_NODE = BIT(9), /* general wlan node tracing */
|
||||
ATH6KL_DBG_WMI = BIT(10), /* wmi tracing */
|
||||
ATH6KL_DBG_TRC = BIT(11), /* generic func tracing */
|
||||
ATH6KL_DBG_SCATTER = BIT(12), /* hif scatter tracing */
|
||||
ATH6KL_DBG_WLAN_CFG = BIT(13), /* cfg80211 i/f file tracing */
|
||||
ATH6KL_DBG_RAW_BYTES = BIT(14), /* dump tx/rx and wmi frames */
|
||||
ATH6KL_DBG_AGGR = BIT(15), /* aggregation */
|
||||
ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */
|
||||
};
|
||||
|
||||
extern unsigned int debug_mask;
|
||||
extern int ath6kl_printk(const char *level, const char *fmt, ...)
|
||||
__attribute__ ((format (printf, 2, 3)));
|
||||
|
||||
#define ath6kl_info(fmt, ...) \
|
||||
ath6kl_printk(KERN_INFO, fmt, ##__VA_ARGS__)
|
||||
#define ath6kl_err(fmt, ...) \
|
||||
ath6kl_printk(KERN_ERR, fmt, ##__VA_ARGS__)
|
||||
#define ath6kl_warn(fmt, ...) \
|
||||
ath6kl_printk(KERN_WARNING, fmt, ##__VA_ARGS__)
|
||||
|
||||
#define AR_DBG_LVL_CHECK(mask) (debug_mask & mask)
|
||||
|
||||
#ifdef CONFIG_ATH6KL_DEBUG
|
||||
#define ath6kl_dbg(mask, fmt, ...) \
|
||||
({ \
|
||||
int rtn; \
|
||||
if (debug_mask & mask) \
|
||||
rtn = ath6kl_printk(KERN_DEBUG, fmt, ##__VA_ARGS__); \
|
||||
else \
|
||||
rtn = 0; \
|
||||
\
|
||||
rtn; \
|
||||
})
|
||||
|
||||
static inline void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask,
|
||||
const char *msg, const void *buf,
|
||||
size_t len)
|
||||
{
|
||||
if (debug_mask & mask) {
|
||||
ath6kl_dbg(mask, "%s\n", msg);
|
||||
print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
void ath6kl_dump_registers(struct ath6kl_device *dev,
|
||||
struct ath6kl_irq_proc_registers *irq_proc_reg,
|
||||
struct ath6kl_irq_enable_reg *irq_en_reg);
|
||||
void dump_cred_dist_stats(struct htc_target *target);
|
||||
#else
|
||||
static inline int ath6kl_dbg(enum ATH6K_DEBUG_MASK dbg_mask,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask,
|
||||
const char *msg, const void *buf,
|
||||
size_t len)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void ath6kl_dump_registers(struct ath6kl_device *dev,
|
||||
struct ath6kl_irq_proc_registers *irq_proc_reg,
|
||||
struct ath6kl_irq_enable_reg *irq_en_reg)
|
||||
{
|
||||
|
||||
}
|
||||
static inline void dump_cred_dist_stats(struct htc_target *target)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2011 Atheros Communications 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 HIF_OPS_H
|
||||
#define HIF_OPS_H
|
||||
|
||||
#include "hif.h"
|
||||
|
||||
static inline int hif_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf,
|
||||
u32 len, u32 request)
|
||||
{
|
||||
return ar->hif_ops->read_write_sync(ar, addr, buf, len, request);
|
||||
}
|
||||
|
||||
static inline int hif_write_async(struct ath6kl *ar, u32 address, u8 *buffer,
|
||||
u32 length, u32 request,
|
||||
struct htc_packet *packet)
|
||||
{
|
||||
return ar->hif_ops->write_async(ar, address, buffer, length,
|
||||
request, packet);
|
||||
}
|
||||
static inline void ath6kl_hif_irq_enable(struct ath6kl *ar)
|
||||
{
|
||||
return ar->hif_ops->irq_enable(ar);
|
||||
}
|
||||
|
||||
static inline void ath6kl_hif_irq_disable(struct ath6kl *ar)
|
||||
{
|
||||
return ar->hif_ops->irq_disable(ar);
|
||||
}
|
||||
|
||||
static inline struct hif_scatter_req *hif_scatter_req_get(struct ath6kl *ar)
|
||||
{
|
||||
return ar->hif_ops->scatter_req_get(ar);
|
||||
}
|
||||
|
||||
static inline void hif_scatter_req_add(struct ath6kl *ar,
|
||||
struct hif_scatter_req *s_req)
|
||||
{
|
||||
return ar->hif_ops->scatter_req_add(ar, s_req);
|
||||
}
|
||||
|
||||
static inline int ath6kl_hif_enable_scatter(struct ath6kl *ar)
|
||||
{
|
||||
return ar->hif_ops->enable_scatter(ar);
|
||||
}
|
||||
|
||||
static inline int ath6kl_hif_scat_req_rw(struct ath6kl *ar,
|
||||
struct hif_scatter_req *scat_req)
|
||||
{
|
||||
return ar->hif_ops->scat_req_rw(ar, scat_req);
|
||||
}
|
||||
|
||||
static inline void ath6kl_hif_cleanup_scatter(struct ath6kl *ar)
|
||||
{
|
||||
return ar->hif_ops->cleanup_scatter(ar);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2011 Atheros Communications 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 HIF_H
|
||||
#define HIF_H
|
||||
|
||||
#include "common.h"
|
||||
#include "core.h"
|
||||
|
||||
#include <linux/scatterlist.h>
|
||||
|
||||
#define BUS_REQUEST_MAX_NUM 64
|
||||
#define HIF_MBOX_BLOCK_SIZE 128
|
||||
#define HIF_MBOX0_BLOCK_SIZE 1
|
||||
|
||||
#define HIF_DMA_BUFFER_SIZE (32 * 1024)
|
||||
#define CMD53_FIXED_ADDRESS 1
|
||||
#define CMD53_INCR_ADDRESS 2
|
||||
|
||||
#define MAX_SCATTER_REQUESTS 4
|
||||
#define MAX_SCATTER_ENTRIES_PER_REQ 16
|
||||
#define MAX_SCATTER_REQ_TRANSFER_SIZE (32 * 1024)
|
||||
|
||||
#define MANUFACTURER_ID_AR6003_BASE 0x300
|
||||
/* SDIO manufacturer ID and Codes */
|
||||
#define MANUFACTURER_ID_ATH6KL_BASE_MASK 0xFF00
|
||||
#define MANUFACTURER_CODE 0x271 /* Atheros */
|
||||
|
||||
/* Mailbox address in SDIO address space */
|
||||
#define HIF_MBOX_BASE_ADDR 0x800
|
||||
#define HIF_MBOX_WIDTH 0x800
|
||||
|
||||
#define HIF_MBOX_END_ADDR (HTC_MAILBOX_NUM_MAX * HIF_MBOX_WIDTH - 1)
|
||||
|
||||
/* version 1 of the chip has only a 12K extended mbox range */
|
||||
#define HIF_MBOX0_EXT_BASE_ADDR 0x4000
|
||||
#define HIF_MBOX0_EXT_WIDTH (12*1024)
|
||||
|
||||
/* GMBOX addresses */
|
||||
#define HIF_GMBOX_BASE_ADDR 0x7000
|
||||
#define HIF_GMBOX_WIDTH 0x4000
|
||||
|
||||
/* interrupt mode register */
|
||||
#define CCCR_SDIO_IRQ_MODE_REG 0xF0
|
||||
|
||||
/* mode to enable special 4-bit interrupt assertion without clock */
|
||||
#define SDIO_IRQ_MODE_ASYNC_4BIT_IRQ (1 << 0)
|
||||
|
||||
struct bus_request {
|
||||
struct list_head list;
|
||||
|
||||
/* request data */
|
||||
u32 address;
|
||||
|
||||
u8 *buffer;
|
||||
u32 length;
|
||||
u32 request;
|
||||
struct htc_packet *packet;
|
||||
int status;
|
||||
|
||||
/* this is a scatter request */
|
||||
struct hif_scatter_req *scat_req;
|
||||
};
|
||||
|
||||
/* direction of transfer (read/write) */
|
||||
#define HIF_READ 0x00000001
|
||||
#define HIF_WRITE 0x00000002
|
||||
#define HIF_DIR_MASK (HIF_READ | HIF_WRITE)
|
||||
|
||||
/*
|
||||
* emode - This indicates the whether the command is to be executed in a
|
||||
* blocking or non-blocking fashion (HIF_SYNCHRONOUS/
|
||||
* HIF_ASYNCHRONOUS). The read/write data paths in HTC have been
|
||||
* implemented using the asynchronous mode allowing the the bus
|
||||
* driver to indicate the completion of operation through the
|
||||
* registered callback routine. The requirement primarily comes
|
||||
* from the contexts these operations get called from (a driver's
|
||||
* transmit context or the ISR context in case of receive).
|
||||
* Support for both of these modes is essential.
|
||||
*/
|
||||
#define HIF_SYNCHRONOUS 0x00000010
|
||||
#define HIF_ASYNCHRONOUS 0x00000020
|
||||
#define HIF_EMODE_MASK (HIF_SYNCHRONOUS | HIF_ASYNCHRONOUS)
|
||||
|
||||
/*
|
||||
* dmode - An interface may support different kinds of commands based on
|
||||
* the tradeoff between the amount of data it can carry and the
|
||||
* setup time. Byte and Block modes are supported (HIF_BYTE_BASIS/
|
||||
* HIF_BLOCK_BASIS). In case of latter, the data is rounded off
|
||||
* to the nearest block size by padding. The size of the block is
|
||||
* configurable at compile time using the HIF_BLOCK_SIZE and is
|
||||
* negotiated with the target during initialization after the
|
||||
* ATH6KL interrupts are enabled.
|
||||
*/
|
||||
#define HIF_BYTE_BASIS 0x00000040
|
||||
#define HIF_BLOCK_BASIS 0x00000080
|
||||
#define HIF_DMODE_MASK (HIF_BYTE_BASIS | HIF_BLOCK_BASIS)
|
||||
|
||||
/*
|
||||
* amode - This indicates if the address has to be incremented on ATH6KL
|
||||
* after every read/write operation (HIF?FIXED_ADDRESS/
|
||||
* HIF_INCREMENTAL_ADDRESS).
|
||||
*/
|
||||
#define HIF_FIXED_ADDRESS 0x00000100
|
||||
#define HIF_INCREMENTAL_ADDRESS 0x00000200
|
||||
#define HIF_AMODE_MASK (HIF_FIXED_ADDRESS | HIF_INCREMENTAL_ADDRESS)
|
||||
|
||||
#define HIF_WR_ASYNC_BYTE_INC \
|
||||
(HIF_WRITE | HIF_ASYNCHRONOUS | \
|
||||
HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS)
|
||||
|
||||
#define HIF_WR_ASYNC_BLOCK_INC \
|
||||
(HIF_WRITE | HIF_ASYNCHRONOUS | \
|
||||
HIF_BLOCK_BASIS | HIF_INCREMENTAL_ADDRESS)
|
||||
|
||||
#define HIF_WR_SYNC_BYTE_FIX \
|
||||
(HIF_WRITE | HIF_SYNCHRONOUS | \
|
||||
HIF_BYTE_BASIS | HIF_FIXED_ADDRESS)
|
||||
|
||||
#define HIF_WR_SYNC_BYTE_INC \
|
||||
(HIF_WRITE | HIF_SYNCHRONOUS | \
|
||||
HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS)
|
||||
|
||||
#define HIF_WR_SYNC_BLOCK_INC \
|
||||
(HIF_WRITE | HIF_SYNCHRONOUS | \
|
||||
HIF_BLOCK_BASIS | HIF_INCREMENTAL_ADDRESS)
|
||||
|
||||
#define HIF_RD_SYNC_BYTE_INC \
|
||||
(HIF_READ | HIF_SYNCHRONOUS | \
|
||||
HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS)
|
||||
|
||||
#define HIF_RD_SYNC_BYTE_FIX \
|
||||
(HIF_READ | HIF_SYNCHRONOUS | \
|
||||
HIF_BYTE_BASIS | HIF_FIXED_ADDRESS)
|
||||
|
||||
#define HIF_RD_ASYNC_BLOCK_FIX \
|
||||
(HIF_READ | HIF_ASYNCHRONOUS | \
|
||||
HIF_BLOCK_BASIS | HIF_FIXED_ADDRESS)
|
||||
|
||||
#define HIF_RD_SYNC_BLOCK_FIX \
|
||||
(HIF_READ | HIF_SYNCHRONOUS | \
|
||||
HIF_BLOCK_BASIS | HIF_FIXED_ADDRESS)
|
||||
|
||||
struct hif_scatter_item {
|
||||
u8 *buf;
|
||||
int len;
|
||||
struct htc_packet *packet;
|
||||
};
|
||||
|
||||
struct hif_scatter_req {
|
||||
struct list_head list;
|
||||
/* address for the read/write operation */
|
||||
u32 addr;
|
||||
|
||||
/* request flags */
|
||||
u32 req;
|
||||
|
||||
/* total length of entire transfer */
|
||||
u32 len;
|
||||
|
||||
bool virt_scat;
|
||||
|
||||
void (*complete) (struct htc_target *, struct hif_scatter_req *);
|
||||
int status;
|
||||
int scat_entries;
|
||||
|
||||
struct bus_request *busrequest;
|
||||
struct scatterlist *sgentries;
|
||||
|
||||
/* bounce buffer for upper layers to copy to/from */
|
||||
u8 *virt_dma_buf;
|
||||
|
||||
struct hif_scatter_item scat_list[1];
|
||||
};
|
||||
|
||||
struct ath6kl_hif_ops {
|
||||
int (*read_write_sync)(struct ath6kl *ar, u32 addr, u8 *buf,
|
||||
u32 len, u32 request);
|
||||
int (*write_async)(struct ath6kl *ar, u32 address, u8 *buffer,
|
||||
u32 length, u32 request, struct htc_packet *packet);
|
||||
|
||||
void (*irq_enable)(struct ath6kl *ar);
|
||||
void (*irq_disable)(struct ath6kl *ar);
|
||||
|
||||
struct hif_scatter_req *(*scatter_req_get)(struct ath6kl *ar);
|
||||
void (*scatter_req_add)(struct ath6kl *ar,
|
||||
struct hif_scatter_req *s_req);
|
||||
int (*enable_scatter)(struct ath6kl *ar);
|
||||
int (*scat_req_rw) (struct ath6kl *ar,
|
||||
struct hif_scatter_req *scat_req);
|
||||
void (*cleanup_scatter)(struct ath6kl *ar);
|
||||
};
|
||||
|
||||
#endif
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,607 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2011 Atheros Communications 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 HTC_H
|
||||
#define HTC_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/* frame header flags */
|
||||
|
||||
/* send direction */
|
||||
#define HTC_FLAGS_NEED_CREDIT_UPDATE (1 << 0)
|
||||
#define HTC_FLAGS_SEND_BUNDLE (1 << 1)
|
||||
|
||||
/* receive direction */
|
||||
#define HTC_FLG_RX_UNUSED (1 << 0)
|
||||
#define HTC_FLG_RX_TRAILER (1 << 1)
|
||||
/* Bundle count maske and shift */
|
||||
#define HTC_FLG_RX_BNDL_CNT (0xF0)
|
||||
#define HTC_FLG_RX_BNDL_CNT_S 4
|
||||
|
||||
#define HTC_HDR_LENGTH (sizeof(struct htc_frame_hdr))
|
||||
#define HTC_MAX_PAYLOAD_LENGTH (4096 - sizeof(struct htc_frame_hdr))
|
||||
|
||||
/* HTC control message IDs */
|
||||
|
||||
#define HTC_MSG_READY_ID 1
|
||||
#define HTC_MSG_CONN_SVC_ID 2
|
||||
#define HTC_MSG_CONN_SVC_RESP_ID 3
|
||||
#define HTC_MSG_SETUP_COMPLETE_ID 4
|
||||
#define HTC_MSG_SETUP_COMPLETE_EX_ID 5
|
||||
|
||||
#define HTC_MAX_CTRL_MSG_LEN 256
|
||||
|
||||
#define HTC_VERSION_2P0 0x00
|
||||
#define HTC_VERSION_2P1 0x01
|
||||
|
||||
#define HTC_SERVICE_META_DATA_MAX_LENGTH 128
|
||||
|
||||
#define HTC_CONN_FLGS_THRESH_LVL_QUAT 0x0
|
||||
#define HTC_CONN_FLGS_THRESH_LVL_HALF 0x1
|
||||
#define HTC_CONN_FLGS_THRESH_LVL_THREE_QUAT 0x2
|
||||
#define HTC_CONN_FLGS_REDUCE_CRED_DRIB 0x4
|
||||
#define HTC_CONN_FLGS_THRESH_MASK 0x3
|
||||
|
||||
/* connect response status codes */
|
||||
#define HTC_SERVICE_SUCCESS 0
|
||||
#define HTC_SERVICE_NOT_FOUND 1
|
||||
#define HTC_SERVICE_FAILED 2
|
||||
|
||||
/* no resources (i.e. no more endpoints) */
|
||||
#define HTC_SERVICE_NO_RESOURCES 3
|
||||
|
||||
/* specific service is not allowing any more endpoints */
|
||||
#define HTC_SERVICE_NO_MORE_EP 4
|
||||
|
||||
/* report record IDs */
|
||||
#define HTC_RECORD_NULL 0
|
||||
#define HTC_RECORD_CREDITS 1
|
||||
#define HTC_RECORD_LOOKAHEAD 2
|
||||
#define HTC_RECORD_LOOKAHEAD_BUNDLE 3
|
||||
|
||||
#define HTC_SETUP_COMP_FLG_RX_BNDL_EN (1 << 0)
|
||||
|
||||
#define MAKE_SERVICE_ID(group, index) \
|
||||
(int)(((int)group << 8) | (int)(index))
|
||||
|
||||
/* NOTE: service ID of 0x0000 is reserved and should never be used */
|
||||
#define HTC_CTRL_RSVD_SVC MAKE_SERVICE_ID(RSVD_SERVICE_GROUP, 1)
|
||||
#define WMI_CONTROL_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 0)
|
||||
#define WMI_DATA_BE_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 1)
|
||||
#define WMI_DATA_BK_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 2)
|
||||
#define WMI_DATA_VI_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 3)
|
||||
#define WMI_DATA_VO_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 4)
|
||||
#define WMI_MAX_SERVICES 5
|
||||
|
||||
/* reserved and used to flush ALL packets */
|
||||
#define HTC_TX_PACKET_TAG_ALL 0
|
||||
#define HTC_SERVICE_TX_PACKET_TAG 1
|
||||
#define HTC_TX_PACKET_TAG_USER_DEFINED (HTC_SERVICE_TX_PACKET_TAG + 9)
|
||||
|
||||
/* more packets on this endpoint are being fetched */
|
||||
#define HTC_RX_FLAGS_INDICATE_MORE_PKTS (1 << 0)
|
||||
|
||||
/* TODO.. for BMI */
|
||||
#define ENDPOINT1 0
|
||||
/* TODO -remove me, but we have to fix BMI first */
|
||||
#define HTC_MAILBOX_NUM_MAX 4
|
||||
|
||||
/* enable send bundle padding for this endpoint */
|
||||
#define HTC_FLGS_TX_BNDL_PAD_EN (1 << 0)
|
||||
#define HTC_EP_ACTIVE ((u32) (1u << 31))
|
||||
|
||||
/* HTC operational parameters */
|
||||
#define HTC_TARGET_RESPONSE_TIMEOUT 2000 /* in ms */
|
||||
#define HTC_TARGET_DEBUG_INTR_MASK 0x01
|
||||
#define HTC_TARGET_CREDIT_INTR_MASK 0xF0
|
||||
|
||||
#define HTC_HOST_MAX_MSG_PER_BUNDLE 8
|
||||
#define HTC_MIN_HTC_MSGS_TO_BUNDLE 2
|
||||
|
||||
/* packet flags */
|
||||
|
||||
#define HTC_RX_PKT_IGNORE_LOOKAHEAD (1 << 0)
|
||||
#define HTC_RX_PKT_REFRESH_HDR (1 << 1)
|
||||
#define HTC_RX_PKT_PART_OF_BUNDLE (1 << 2)
|
||||
#define HTC_RX_PKT_NO_RECYCLE (1 << 3)
|
||||
|
||||
#define NUM_CONTROL_BUFFERS 8
|
||||
#define NUM_CONTROL_TX_BUFFERS 2
|
||||
#define NUM_CONTROL_RX_BUFFERS (NUM_CONTROL_BUFFERS - NUM_CONTROL_TX_BUFFERS)
|
||||
|
||||
#define HTC_RECV_WAIT_BUFFERS (1 << 0)
|
||||
#define HTC_OP_STATE_STOPPING (1 << 0)
|
||||
|
||||
/*
|
||||
* The frame header length and message formats defined herein were selected
|
||||
* to accommodate optimal alignment for target processing. This reduces
|
||||
* code size and improves performance. Any changes to the header length may
|
||||
* alter the alignment and cause exceptions on the target. When adding to
|
||||
* the messagestructures insure that fields are properly aligned.
|
||||
*/
|
||||
|
||||
/* HTC frame header
|
||||
*
|
||||
* NOTE: do not remove or re-arrange the fields, these are minimally
|
||||
* required to take advantage of 4-byte lookaheads in some hardware
|
||||
* implementations.
|
||||
*/
|
||||
struct htc_frame_hdr {
|
||||
u8 eid;
|
||||
u8 flags;
|
||||
|
||||
/* length of data (including trailer) that follows the header */
|
||||
__le16 payld_len;
|
||||
|
||||
/* end of 4-byte lookahead */
|
||||
|
||||
u8 ctrl[2];
|
||||
} __packed;
|
||||
|
||||
/* HTC ready message */
|
||||
struct htc_ready_msg {
|
||||
__le16 msg_id;
|
||||
__le16 cred_cnt;
|
||||
__le16 cred_sz;
|
||||
u8 max_ep;
|
||||
u8 pad;
|
||||
} __packed;
|
||||
|
||||
/* extended HTC ready message */
|
||||
struct htc_ready_ext_msg {
|
||||
struct htc_ready_msg ver2_0_info;
|
||||
u8 htc_ver;
|
||||
u8 msg_per_htc_bndl;
|
||||
} __packed;
|
||||
|
||||
/* connect service */
|
||||
struct htc_conn_service_msg {
|
||||
__le16 msg_id;
|
||||
__le16 svc_id;
|
||||
__le16 conn_flags;
|
||||
u8 svc_meta_len;
|
||||
u8 pad;
|
||||
} __packed;
|
||||
|
||||
/* connect response */
|
||||
struct htc_conn_service_resp {
|
||||
__le16 msg_id;
|
||||
__le16 svc_id;
|
||||
u8 status;
|
||||
u8 eid;
|
||||
__le16 max_msg_sz;
|
||||
u8 svc_meta_len;
|
||||
u8 pad;
|
||||
} __packed;
|
||||
|
||||
struct htc_setup_comp_msg {
|
||||
__le16 msg_id;
|
||||
} __packed;
|
||||
|
||||
/* extended setup completion message */
|
||||
struct htc_setup_comp_ext_msg {
|
||||
__le16 msg_id;
|
||||
__le32 flags;
|
||||
u8 msg_per_rxbndl;
|
||||
u8 Rsvd[3];
|
||||
} __packed;
|
||||
|
||||
struct htc_record_hdr {
|
||||
u8 rec_id;
|
||||
u8 len;
|
||||
} __packed;
|
||||
|
||||
struct htc_credit_report {
|
||||
u8 eid;
|
||||
u8 credits;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* NOTE: The lk_ahd array is guarded by a pre_valid
|
||||
* and Post Valid guard bytes. The pre_valid bytes must
|
||||
* equal the inverse of the post_valid byte.
|
||||
*/
|
||||
struct htc_lookahead_report {
|
||||
u8 pre_valid;
|
||||
u8 lk_ahd[4];
|
||||
u8 post_valid;
|
||||
} __packed;
|
||||
|
||||
struct htc_bundle_lkahd_rpt {
|
||||
u8 lk_ahd[4];
|
||||
} __packed;
|
||||
|
||||
/* Current service IDs */
|
||||
|
||||
enum htc_service_grp_ids {
|
||||
RSVD_SERVICE_GROUP = 0,
|
||||
WMI_SERVICE_GROUP = 1,
|
||||
|
||||
HTC_TEST_GROUP = 254,
|
||||
HTC_SERVICE_GROUP_LAST = 255
|
||||
};
|
||||
|
||||
/* ------ endpoint IDS ------ */
|
||||
|
||||
enum htc_endpoint_id {
|
||||
ENDPOINT_UNUSED = -1,
|
||||
ENDPOINT_0 = 0,
|
||||
ENDPOINT_1 = 1,
|
||||
ENDPOINT_2 = 2,
|
||||
ENDPOINT_3,
|
||||
ENDPOINT_4,
|
||||
ENDPOINT_5,
|
||||
ENDPOINT_6,
|
||||
ENDPOINT_7,
|
||||
ENDPOINT_8,
|
||||
ENDPOINT_MAX,
|
||||
};
|
||||
|
||||
struct htc_tx_packet_info {
|
||||
u16 tag;
|
||||
int cred_used;
|
||||
u8 flags;
|
||||
int seqno;
|
||||
};
|
||||
|
||||
struct htc_rx_packet_info {
|
||||
u32 exp_hdr;
|
||||
u32 rx_flags;
|
||||
u32 indicat_flags;
|
||||
};
|
||||
|
||||
struct htc_target;
|
||||
|
||||
/* wrapper around endpoint-specific packets */
|
||||
struct htc_packet {
|
||||
struct list_head list;
|
||||
|
||||
/* caller's per packet specific context */
|
||||
void *pkt_cntxt;
|
||||
|
||||
/*
|
||||
* the true buffer start , the caller can store the real
|
||||
* buffer start here. In receive callbacks, the HTC layer
|
||||
* sets buf to the start of the payload past the header.
|
||||
* This field allows the caller to reset buf when it recycles
|
||||
* receive packets back to HTC.
|
||||
*/
|
||||
u8 *buf_start;
|
||||
|
||||
/*
|
||||
* Pointer to the start of the buffer. In the transmit
|
||||
* direction this points to the start of the payload. In the
|
||||
* receive direction, however, the buffer when queued up
|
||||
* points to the start of the HTC header but when returned
|
||||
* to the caller points to the start of the payload
|
||||
*/
|
||||
u8 *buf;
|
||||
u32 buf_len;
|
||||
|
||||
/* actual length of payload */
|
||||
u32 act_len;
|
||||
|
||||
/* endpoint that this packet was sent/recv'd from */
|
||||
enum htc_endpoint_id endpoint;
|
||||
|
||||
/* completion status */
|
||||
|
||||
int status;
|
||||
union {
|
||||
struct htc_tx_packet_info tx;
|
||||
struct htc_rx_packet_info rx;
|
||||
} info;
|
||||
|
||||
void (*completion) (struct htc_target *, struct htc_packet *);
|
||||
struct htc_target *context;
|
||||
};
|
||||
|
||||
enum htc_send_full_action {
|
||||
HTC_SEND_FULL_KEEP = 0,
|
||||
HTC_SEND_FULL_DROP = 1,
|
||||
};
|
||||
|
||||
struct htc_ep_callbacks {
|
||||
void (*rx) (struct htc_target *, struct htc_packet *);
|
||||
void (*rx_refill) (struct htc_target *, enum htc_endpoint_id endpoint);
|
||||
enum htc_send_full_action (*tx_full) (struct htc_target *,
|
||||
struct htc_packet *);
|
||||
struct htc_packet *(*rx_allocthresh) (struct htc_target *,
|
||||
enum htc_endpoint_id, int);
|
||||
int rx_alloc_thresh;
|
||||
int rx_refill_thresh;
|
||||
};
|
||||
|
||||
/* service connection information */
|
||||
struct htc_service_connect_req {
|
||||
u16 svc_id;
|
||||
u16 conn_flags;
|
||||
struct htc_ep_callbacks ep_cb;
|
||||
int max_txq_depth;
|
||||
u32 flags;
|
||||
unsigned int max_rxmsg_sz;
|
||||
};
|
||||
|
||||
/* service connection response information */
|
||||
struct htc_service_connect_resp {
|
||||
u8 buf_len;
|
||||
u8 act_len;
|
||||
enum htc_endpoint_id endpoint;
|
||||
unsigned int len_max;
|
||||
u8 resp_code;
|
||||
};
|
||||
|
||||
/* endpoint distributionstructure */
|
||||
struct htc_endpoint_credit_dist {
|
||||
struct list_head list;
|
||||
|
||||
/* Service ID (set by HTC) */
|
||||
u16 svc_id;
|
||||
|
||||
/* endpoint for this distributionstruct (set by HTC) */
|
||||
enum htc_endpoint_id endpoint;
|
||||
|
||||
u32 dist_flags;
|
||||
|
||||
/*
|
||||
* credits for normal operation, anything above this
|
||||
* indicates the endpoint is over-subscribed.
|
||||
*/
|
||||
int cred_norm;
|
||||
|
||||
/* floor for credit distribution */
|
||||
int cred_min;
|
||||
|
||||
int cred_assngd;
|
||||
|
||||
/* current credits available */
|
||||
int credits;
|
||||
|
||||
/*
|
||||
* pending credits to distribute on this endpoint, this
|
||||
* is set by HTC when credit reports arrive. The credit
|
||||
* distribution functions sets this to zero when it distributes
|
||||
* the credits.
|
||||
*/
|
||||
int cred_to_dist;
|
||||
|
||||
/*
|
||||
* the number of credits that the current pending TX packet needs
|
||||
* to transmit. This is set by HTC when endpoint needs credits in
|
||||
* order to transmit.
|
||||
*/
|
||||
int seek_cred;
|
||||
|
||||
/* size in bytes of each credit */
|
||||
int cred_sz;
|
||||
|
||||
/* credits required for a maximum sized messages */
|
||||
int cred_per_msg;
|
||||
|
||||
/* reserved for HTC use */
|
||||
void *htc_rsvd;
|
||||
|
||||
/*
|
||||
* current depth of TX queue , i.e. messages waiting for credits
|
||||
* This field is valid only when HTC_CREDIT_DIST_ACTIVITY_CHANGE
|
||||
* or HTC_CREDIT_DIST_SEND_COMPLETE is indicated on an endpoint
|
||||
* that has non-zero credits to recover.
|
||||
*/
|
||||
int txq_depth;
|
||||
};
|
||||
|
||||
/*
|
||||
* credit distibution code that is passed into the distrbution function,
|
||||
* there are mandatory and optional codes that must be handled
|
||||
*/
|
||||
enum htc_credit_dist_reason {
|
||||
HTC_CREDIT_DIST_SEND_COMPLETE = 0,
|
||||
HTC_CREDIT_DIST_ACTIVITY_CHANGE = 1,
|
||||
HTC_CREDIT_DIST_SEEK_CREDITS,
|
||||
};
|
||||
|
||||
struct htc_credit_state_info {
|
||||
int total_avail_credits;
|
||||
int cur_free_credits;
|
||||
struct list_head lowestpri_ep_dist;
|
||||
};
|
||||
|
||||
/* endpoint statistics */
|
||||
struct htc_endpoint_stats {
|
||||
/*
|
||||
* number of times the host set the credit-low flag in a send
|
||||
* message on this endpoint
|
||||
*/
|
||||
u32 cred_low_indicate;
|
||||
|
||||
u32 tx_issued;
|
||||
u32 tx_pkt_bundled;
|
||||
u32 tx_bundles;
|
||||
u32 tx_dropped;
|
||||
|
||||
/* running count of total credit reports received for this endpoint */
|
||||
u32 tx_cred_rpt;
|
||||
|
||||
/* credit reports received from this endpoint's RX packets */
|
||||
u32 cred_rpt_from_rx;
|
||||
|
||||
/* credit reports received from RX packets of other endpoints */
|
||||
u32 cred_rpt_from_other;
|
||||
|
||||
/* credit reports received from endpoint 0 RX packets */
|
||||
u32 cred_rpt_ep0;
|
||||
|
||||
/* count of credits received via Rx packets on this endpoint */
|
||||
u32 cred_from_rx;
|
||||
|
||||
/* count of credits received via another endpoint */
|
||||
u32 cred_from_other;
|
||||
|
||||
/* count of credits received via another endpoint */
|
||||
u32 cred_from_ep0;
|
||||
|
||||
/* count of consummed credits */
|
||||
u32 cred_cosumd;
|
||||
|
||||
/* count of credits returned */
|
||||
u32 cred_retnd;
|
||||
|
||||
u32 rx_pkts;
|
||||
|
||||
/* count of lookahead records found in Rx msg */
|
||||
u32 rx_lkahds;
|
||||
|
||||
/* count of recv packets received in a bundle */
|
||||
u32 rx_bundl;
|
||||
|
||||
/* count of number of bundled lookaheads */
|
||||
u32 rx_bundle_lkahd;
|
||||
|
||||
/* count of the number of bundle indications from the HTC header */
|
||||
u32 rx_bundle_from_hdr;
|
||||
|
||||
/* the number of times the recv allocation threshold was hit */
|
||||
u32 rx_alloc_thresh_hit;
|
||||
|
||||
/* total number of bytes */
|
||||
u32 rxalloc_thresh_byte;
|
||||
};
|
||||
|
||||
struct htc_endpoint {
|
||||
enum htc_endpoint_id eid;
|
||||
u16 svc_id;
|
||||
struct list_head txq;
|
||||
struct list_head rx_bufq;
|
||||
struct htc_endpoint_credit_dist cred_dist;
|
||||
struct htc_ep_callbacks ep_cb;
|
||||
int max_txq_depth;
|
||||
int len_max;
|
||||
int tx_proc_cnt;
|
||||
int rx_proc_cnt;
|
||||
struct htc_target *target;
|
||||
u8 seqno;
|
||||
u32 conn_flags;
|
||||
struct htc_endpoint_stats ep_st;
|
||||
};
|
||||
|
||||
struct htc_control_buffer {
|
||||
struct htc_packet packet;
|
||||
u8 *buf;
|
||||
};
|
||||
|
||||
struct ath6kl_device;
|
||||
|
||||
/* our HTC target state */
|
||||
struct htc_target {
|
||||
struct htc_endpoint endpoint[ENDPOINT_MAX];
|
||||
struct list_head cred_dist_list;
|
||||
struct list_head free_ctrl_txbuf;
|
||||
struct list_head free_ctrl_rxbuf;
|
||||
struct htc_credit_state_info *cred_dist_cntxt;
|
||||
int tgt_creds;
|
||||
unsigned int tgt_cred_sz;
|
||||
spinlock_t htc_lock;
|
||||
spinlock_t rx_lock;
|
||||
spinlock_t tx_lock;
|
||||
struct ath6kl_device *dev;
|
||||
u32 htc_flags;
|
||||
u32 rx_st_flags;
|
||||
enum htc_endpoint_id ep_waiting;
|
||||
u8 htc_tgt_ver;
|
||||
|
||||
/* max messages per bundle for HTC */
|
||||
int msg_per_bndl_max;
|
||||
|
||||
bool tx_bndl_enable;
|
||||
int rx_bndl_enable;
|
||||
int max_rx_bndl_sz;
|
||||
int max_tx_bndl_sz;
|
||||
|
||||
u32 block_sz;
|
||||
u32 block_mask;
|
||||
|
||||
int max_scat_entries;
|
||||
int max_xfer_szper_scatreq;
|
||||
|
||||
int chk_irq_status_cnt;
|
||||
};
|
||||
|
||||
void *ath6kl_htc_create(struct ath6kl *ar);
|
||||
void ath6kl_htc_set_credit_dist(struct htc_target *target,
|
||||
struct htc_credit_state_info *cred_info,
|
||||
u16 svc_pri_order[], int len);
|
||||
int ath6kl_htc_wait_target(struct htc_target *target);
|
||||
int ath6kl_htc_start(struct htc_target *target);
|
||||
int ath6kl_htc_conn_service(struct htc_target *target,
|
||||
struct htc_service_connect_req *req,
|
||||
struct htc_service_connect_resp *resp);
|
||||
int ath6kl_htc_tx(struct htc_target *target, struct htc_packet *packet);
|
||||
void ath6kl_htc_stop(struct htc_target *target);
|
||||
void ath6kl_htc_cleanup(struct htc_target *target);
|
||||
void ath6kl_htc_flush_txep(struct htc_target *target,
|
||||
enum htc_endpoint_id endpoint, u16 tag);
|
||||
void ath6kl_htc_flush_rx_buf(struct htc_target *target);
|
||||
void ath6kl_htc_indicate_activity_change(struct htc_target *target,
|
||||
enum htc_endpoint_id endpoint,
|
||||
bool active);
|
||||
int ath6kl_htc_get_rxbuf_num(struct htc_target *target,
|
||||
enum htc_endpoint_id endpoint);
|
||||
int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target,
|
||||
struct list_head *pktq);
|
||||
int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target,
|
||||
u32 msg_look_ahead[], int *n_pkts);
|
||||
|
||||
static inline void set_htc_pkt_info(struct htc_packet *packet, void *context,
|
||||
u8 *buf, unsigned int len,
|
||||
enum htc_endpoint_id eid, u16 tag)
|
||||
{
|
||||
packet->pkt_cntxt = context;
|
||||
packet->buf = buf;
|
||||
packet->act_len = len;
|
||||
packet->endpoint = eid;
|
||||
packet->info.tx.tag = tag;
|
||||
}
|
||||
|
||||
static inline void htc_rxpkt_reset(struct htc_packet *packet)
|
||||
{
|
||||
packet->buf = packet->buf_start;
|
||||
packet->act_len = 0;
|
||||
}
|
||||
|
||||
static inline void set_htc_rxpkt_info(struct htc_packet *packet, void *context,
|
||||
u8 *buf, unsigned long len,
|
||||
enum htc_endpoint_id eid)
|
||||
{
|
||||
packet->pkt_cntxt = context;
|
||||
packet->buf = buf;
|
||||
packet->buf_start = buf;
|
||||
packet->buf_len = len;
|
||||
packet->endpoint = eid;
|
||||
}
|
||||
|
||||
static inline int get_queue_depth(struct list_head *queue)
|
||||
{
|
||||
struct list_head *tmp_list;
|
||||
int depth = 0;
|
||||
|
||||
list_for_each(tmp_list, queue)
|
||||
depth++;
|
||||
|
||||
return depth;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,641 @@
|
|||
/*
|
||||
* Copyright (c) 2007-2011 Atheros Communications 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 "core.h"
|
||||
#include "target.h"
|
||||
#include "hif-ops.h"
|
||||
#include "htc_hif.h"
|
||||
#include "debug.h"
|
||||
|
||||
#define MAILBOX_FOR_BLOCK_SIZE 1
|
||||
|
||||
#define ATH6KL_TIME_QUANTUM 10 /* in ms */
|
||||
|
||||
static int ath6kldev_cp_scat_dma_buf(struct hif_scatter_req *req, bool from_dma)
|
||||
{
|
||||
u8 *buf;
|
||||
int i;
|
||||
|
||||
buf = req->virt_dma_buf;
|
||||
|
||||
for (i = 0; i < req->scat_entries; i++) {
|
||||
|
||||
if (from_dma)
|
||||
memcpy(req->scat_list[i].buf, buf,
|
||||
req->scat_list[i].len);
|
||||
else
|
||||
memcpy(buf, req->scat_list[i].buf,
|
||||
req->scat_list[i].len);
|
||||
|
||||
buf += req->scat_list[i].len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath6kldev_rw_comp_handler(void *context, int status)
|
||||
{
|
||||
struct htc_packet *packet = context;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_HTC_RECV,
|
||||
"ath6kldev_rw_comp_handler (pkt:0x%p , status: %d\n",
|
||||
packet, status);
|
||||
|
||||
packet->status = status;
|
||||
packet->completion(packet->context, packet);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kldev_proc_dbg_intr(struct ath6kl_device *dev)
|
||||
{
|
||||
u32 dummy;
|
||||
int status;
|
||||
|
||||
ath6kl_err("target debug interrupt\n");
|
||||
|
||||
ath6kl_target_failure(dev->ar);
|
||||
|
||||
/*
|
||||
* read counter to clear the interrupt, the debug error interrupt is
|
||||
* counter 0.
|
||||
*/
|
||||
status = hif_read_write_sync(dev->ar, COUNT_DEC_ADDRESS,
|
||||
(u8 *)&dummy, 4, HIF_RD_SYNC_BYTE_INC);
|
||||
if (status)
|
||||
WARN_ON(1);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* mailbox recv message polling */
|
||||
int ath6kldev_poll_mboxmsg_rx(struct ath6kl_device *dev, u32 *lk_ahd,
|
||||
int timeout)
|
||||
{
|
||||
struct ath6kl_irq_proc_registers *rg;
|
||||
int status = 0, i;
|
||||
u8 htc_mbox = 1 << HTC_MAILBOX;
|
||||
|
||||
for (i = timeout / ATH6KL_TIME_QUANTUM; i > 0; i--) {
|
||||
/* this is the standard HIF way, load the reg table */
|
||||
status = hif_read_write_sync(dev->ar, HOST_INT_STATUS_ADDRESS,
|
||||
(u8 *) &dev->irq_proc_reg,
|
||||
sizeof(dev->irq_proc_reg),
|
||||
HIF_RD_SYNC_BYTE_INC);
|
||||
|
||||
if (status) {
|
||||
ath6kl_err("failed to read reg table\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
/* check for MBOX data and valid lookahead */
|
||||
if (dev->irq_proc_reg.host_int_status & htc_mbox) {
|
||||
if (dev->irq_proc_reg.rx_lkahd_valid &
|
||||
htc_mbox) {
|
||||
/*
|
||||
* Mailbox has a message and the look ahead
|
||||
* is valid.
|
||||
*/
|
||||
rg = &dev->irq_proc_reg;
|
||||
*lk_ahd =
|
||||
le32_to_cpu(rg->rx_lkahd[HTC_MAILBOX]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* delay a little */
|
||||
mdelay(ATH6KL_TIME_QUANTUM);
|
||||
ath6kl_dbg(ATH6KL_DBG_HTC_RECV, "retry mbox poll : %d\n", i);
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
ath6kl_err("timeout waiting for recv message\n");
|
||||
status = -ETIME;
|
||||
/* check if the target asserted */
|
||||
if (dev->irq_proc_reg.counter_int_status &
|
||||
ATH6KL_TARGET_DEBUG_INTR_MASK)
|
||||
/*
|
||||
* Target failure handler will be called in case of
|
||||
* an assert.
|
||||
*/
|
||||
ath6kldev_proc_dbg_intr(dev);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable packet reception (used in case the host runs out of buffers)
|
||||
* using the interrupt enable registers through the host I/F
|
||||
*/
|
||||
int ath6kldev_rx_control(struct ath6kl_device *dev, bool enable_rx)
|
||||
{
|
||||
struct ath6kl_irq_enable_reg regs;
|
||||
int status = 0;
|
||||
|
||||
/* take the lock to protect interrupt enable shadows */
|
||||
spin_lock_bh(&dev->lock);
|
||||
|
||||
if (enable_rx)
|
||||
dev->irq_en_reg.int_status_en |=
|
||||
SM(INT_STATUS_ENABLE_MBOX_DATA, 0x01);
|
||||
else
|
||||
dev->irq_en_reg.int_status_en &=
|
||||
~SM(INT_STATUS_ENABLE_MBOX_DATA, 0x01);
|
||||
|
||||
memcpy(®s, &dev->irq_en_reg, sizeof(regs));
|
||||
|
||||
spin_unlock_bh(&dev->lock);
|
||||
|
||||
status = hif_read_write_sync(dev->ar, INT_STATUS_ENABLE_ADDRESS,
|
||||
®s.int_status_en,
|
||||
sizeof(struct ath6kl_irq_enable_reg),
|
||||
HIF_WR_SYNC_BYTE_INC);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int ath6kldev_submit_scat_req(struct ath6kl_device *dev,
|
||||
struct hif_scatter_req *scat_req, bool read)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
if (read) {
|
||||
scat_req->req = HIF_RD_SYNC_BLOCK_FIX;
|
||||
scat_req->addr = dev->ar->mbox_info.htc_addr;
|
||||
} else {
|
||||
scat_req->req = HIF_WR_ASYNC_BLOCK_INC;
|
||||
|
||||
scat_req->addr =
|
||||
(scat_req->len > HIF_MBOX_WIDTH) ?
|
||||
dev->ar->mbox_info.htc_ext_addr :
|
||||
dev->ar->mbox_info.htc_addr;
|
||||
}
|
||||
|
||||
ath6kl_dbg((ATH6KL_DBG_HTC_RECV | ATH6KL_DBG_HTC_SEND),
|
||||
"ath6kldev_submit_scat_req, entries: %d, total len: %d mbox:0x%X (mode: %s : %s)\n",
|
||||
scat_req->scat_entries, scat_req->len,
|
||||
scat_req->addr, !read ? "async" : "sync",
|
||||
(read) ? "rd" : "wr");
|
||||
|
||||
if (!read && scat_req->virt_scat) {
|
||||
status = ath6kldev_cp_scat_dma_buf(scat_req, false);
|
||||
if (status) {
|
||||
scat_req->status = status;
|
||||
scat_req->complete(dev->ar->htc_target, scat_req);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
status = ath6kl_hif_scat_req_rw(dev->ar, scat_req);
|
||||
|
||||
if (read) {
|
||||
/* in sync mode, we can touch the scatter request */
|
||||
scat_req->status = status;
|
||||
if (!status && scat_req->virt_scat)
|
||||
scat_req->status =
|
||||
ath6kldev_cp_scat_dma_buf(scat_req, true);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int ath6kldev_proc_counter_intr(struct ath6kl_device *dev)
|
||||
{
|
||||
u8 counter_int_status;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_IRQ, "counter interrupt\n");
|
||||
|
||||
counter_int_status = dev->irq_proc_reg.counter_int_status &
|
||||
dev->irq_en_reg.cntr_int_status_en;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_IRQ,
|
||||
"valid interrupt source(s) in COUNTER_INT_STATUS: 0x%x\n",
|
||||
counter_int_status);
|
||||
|
||||
/*
|
||||
* NOTE: other modules like GMBOX may use the counter interrupt for
|
||||
* credit flow control on other counters, we only need to check for
|
||||
* the debug assertion counter interrupt.
|
||||
*/
|
||||
if (counter_int_status & ATH6KL_TARGET_DEBUG_INTR_MASK)
|
||||
return ath6kldev_proc_dbg_intr(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kldev_proc_err_intr(struct ath6kl_device *dev)
|
||||
{
|
||||
int status;
|
||||
u8 error_int_status;
|
||||
u8 reg_buf[4];
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_IRQ, "error interrupt\n");
|
||||
|
||||
error_int_status = dev->irq_proc_reg.error_int_status & 0x0F;
|
||||
if (!error_int_status) {
|
||||
WARN_ON(1);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_IRQ,
|
||||
"valid interrupt source(s) in ERROR_INT_STATUS: 0x%x\n",
|
||||
error_int_status);
|
||||
|
||||
if (MS(ERROR_INT_STATUS_WAKEUP, error_int_status))
|
||||
ath6kl_dbg(ATH6KL_DBG_IRQ, "error : wakeup\n");
|
||||
|
||||
if (MS(ERROR_INT_STATUS_RX_UNDERFLOW, error_int_status))
|
||||
ath6kl_err("rx underflow\n");
|
||||
|
||||
if (MS(ERROR_INT_STATUS_TX_OVERFLOW, error_int_status))
|
||||
ath6kl_err("tx overflow\n");
|
||||
|
||||
/* Clear the interrupt */
|
||||
dev->irq_proc_reg.error_int_status &= ~error_int_status;
|
||||
|
||||
/* set W1C value to clear the interrupt, this hits the register first */
|
||||
reg_buf[0] = error_int_status;
|
||||
reg_buf[1] = 0;
|
||||
reg_buf[2] = 0;
|
||||
reg_buf[3] = 0;
|
||||
|
||||
status = hif_read_write_sync(dev->ar, ERROR_INT_STATUS_ADDRESS,
|
||||
reg_buf, 4, HIF_WR_SYNC_BYTE_FIX);
|
||||
|
||||
if (status)
|
||||
WARN_ON(1);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int ath6kldev_proc_cpu_intr(struct ath6kl_device *dev)
|
||||
{
|
||||
int status;
|
||||
u8 cpu_int_status;
|
||||
u8 reg_buf[4];
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_IRQ, "cpu interrupt\n");
|
||||
|
||||
cpu_int_status = dev->irq_proc_reg.cpu_int_status &
|
||||
dev->irq_en_reg.cpu_int_status_en;
|
||||
if (!cpu_int_status) {
|
||||
WARN_ON(1);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_IRQ,
|
||||
"valid interrupt source(s) in CPU_INT_STATUS: 0x%x\n",
|
||||
cpu_int_status);
|
||||
|
||||
/* Clear the interrupt */
|
||||
dev->irq_proc_reg.cpu_int_status &= ~cpu_int_status;
|
||||
|
||||
/*
|
||||
* Set up the register transfer buffer to hit the register 4 times ,
|
||||
* this is done to make the access 4-byte aligned to mitigate issues
|
||||
* with host bus interconnects that restrict bus transfer lengths to
|
||||
* be a multiple of 4-bytes.
|
||||
*/
|
||||
|
||||
/* set W1C value to clear the interrupt, this hits the register first */
|
||||
reg_buf[0] = cpu_int_status;
|
||||
/* the remaining are set to zero which have no-effect */
|
||||
reg_buf[1] = 0;
|
||||
reg_buf[2] = 0;
|
||||
reg_buf[3] = 0;
|
||||
|
||||
status = hif_read_write_sync(dev->ar, CPU_INT_STATUS_ADDRESS,
|
||||
reg_buf, 4, HIF_WR_SYNC_BYTE_FIX);
|
||||
|
||||
if (status)
|
||||
WARN_ON(1);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* process pending interrupts synchronously */
|
||||
static int proc_pending_irqs(struct ath6kl_device *dev, bool *done)
|
||||
{
|
||||
struct ath6kl_irq_proc_registers *rg;
|
||||
int status = 0;
|
||||
u8 host_int_status = 0;
|
||||
u32 lk_ahd = 0;
|
||||
u8 htc_mbox = 1 << HTC_MAILBOX;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_IRQ, "proc_pending_irqs: (dev: 0x%p)\n", dev);
|
||||
|
||||
/*
|
||||
* NOTE: HIF implementation guarantees that the context of this
|
||||
* call allows us to perform SYNCHRONOUS I/O, that is we can block,
|
||||
* sleep or call any API that can block or switch thread/task
|
||||
* contexts. This is a fully schedulable context.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Process pending intr only when int_status_en is clear, it may
|
||||
* result in unnecessary bus transaction otherwise. Target may be
|
||||
* unresponsive at the time.
|
||||
*/
|
||||
if (dev->irq_en_reg.int_status_en) {
|
||||
/*
|
||||
* Read the first 28 bytes of the HTC register table. This
|
||||
* will yield us the value of different int status
|
||||
* registers and the lookahead registers.
|
||||
*
|
||||
* length = sizeof(int_status) + sizeof(cpu_int_status)
|
||||
* + sizeof(error_int_status) +
|
||||
* sizeof(counter_int_status) +
|
||||
* sizeof(mbox_frame) + sizeof(rx_lkahd_valid)
|
||||
* + sizeof(hole) + sizeof(rx_lkahd) +
|
||||
* sizeof(int_status_en) +
|
||||
* sizeof(cpu_int_status_en) +
|
||||
* sizeof(err_int_status_en) +
|
||||
* sizeof(cntr_int_status_en);
|
||||
*/
|
||||
status = hif_read_write_sync(dev->ar, HOST_INT_STATUS_ADDRESS,
|
||||
(u8 *) &dev->irq_proc_reg,
|
||||
sizeof(dev->irq_proc_reg),
|
||||
HIF_RD_SYNC_BYTE_INC);
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
if (AR_DBG_LVL_CHECK(ATH6KL_DBG_IRQ))
|
||||
ath6kl_dump_registers(dev, &dev->irq_proc_reg,
|
||||
&dev->irq_en_reg);
|
||||
|
||||
/* Update only those registers that are enabled */
|
||||
host_int_status = dev->irq_proc_reg.host_int_status &
|
||||
dev->irq_en_reg.int_status_en;
|
||||
|
||||
/* Look at mbox status */
|
||||
if (host_int_status & htc_mbox) {
|
||||
/*
|
||||
* Mask out pending mbox value, we use "lookAhead as
|
||||
* the real flag for mbox processing.
|
||||
*/
|
||||
host_int_status &= ~htc_mbox;
|
||||
if (dev->irq_proc_reg.rx_lkahd_valid &
|
||||
htc_mbox) {
|
||||
rg = &dev->irq_proc_reg;
|
||||
lk_ahd = le32_to_cpu(rg->rx_lkahd[HTC_MAILBOX]);
|
||||
if (!lk_ahd)
|
||||
ath6kl_err("lookAhead is zero!\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!host_int_status && !lk_ahd) {
|
||||
*done = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (lk_ahd) {
|
||||
int fetched = 0;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_IRQ,
|
||||
"pending mailbox msg, lk_ahd: 0x%X\n", lk_ahd);
|
||||
/*
|
||||
* Mailbox Interrupt, the HTC layer may issue async
|
||||
* requests to empty the mailbox. When emptying the recv
|
||||
* mailbox we use the async handler above called from the
|
||||
* completion routine of the callers read request. This can
|
||||
* improve performance by reducing context switching when
|
||||
* we rapidly pull packets.
|
||||
*/
|
||||
status = ath6kl_htc_rxmsg_pending_handler(dev->htc_cnxt,
|
||||
&lk_ahd, &fetched);
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
if (!fetched)
|
||||
/*
|
||||
* HTC could not pull any messages out due to lack
|
||||
* of resources.
|
||||
*/
|
||||
dev->htc_cnxt->chk_irq_status_cnt = 0;
|
||||
}
|
||||
|
||||
/* now handle the rest of them */
|
||||
ath6kl_dbg(ATH6KL_DBG_IRQ,
|
||||
"valid interrupt source(s) for other interrupts: 0x%x\n",
|
||||
host_int_status);
|
||||
|
||||
if (MS(HOST_INT_STATUS_CPU, host_int_status)) {
|
||||
/* CPU Interrupt */
|
||||
status = ath6kldev_proc_cpu_intr(dev);
|
||||
if (status)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (MS(HOST_INT_STATUS_ERROR, host_int_status)) {
|
||||
/* Error Interrupt */
|
||||
status = ath6kldev_proc_err_intr(dev);
|
||||
if (status)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (MS(HOST_INT_STATUS_COUNTER, host_int_status))
|
||||
/* Counter Interrupt */
|
||||
status = ath6kldev_proc_counter_intr(dev);
|
||||
|
||||
out:
|
||||
/*
|
||||
* An optimization to bypass reading the IRQ status registers
|
||||
* unecessarily which can re-wake the target, if upper layers
|
||||
* determine that we are in a low-throughput mode, we can rely on
|
||||
* taking another interrupt rather than re-checking the status
|
||||
* registers which can re-wake the target.
|
||||
*
|
||||
* NOTE : for host interfaces that makes use of detecting pending
|
||||
* mbox messages at hif can not use this optimization due to
|
||||
* possible side effects, SPI requires the host to drain all
|
||||
* messages from the mailbox before exiting the ISR routine.
|
||||
*/
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_IRQ,
|
||||
"bypassing irq status re-check, forcing done\n");
|
||||
|
||||
if (!dev->htc_cnxt->chk_irq_status_cnt)
|
||||
*done = true;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_IRQ,
|
||||
"proc_pending_irqs: (done:%d, status=%d\n", *done, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* interrupt handler, kicks off all interrupt processing */
|
||||
int ath6kldev_intr_bh_handler(struct ath6kl *ar)
|
||||
{
|
||||
struct ath6kl_device *dev = ar->htc_target->dev;
|
||||
int status = 0;
|
||||
bool done = false;
|
||||
|
||||
/*
|
||||
* Reset counter used to flag a re-scan of IRQ status registers on
|
||||
* the target.
|
||||
*/
|
||||
dev->htc_cnxt->chk_irq_status_cnt = 0;
|
||||
|
||||
/*
|
||||
* IRQ processing is synchronous, interrupt status registers can be
|
||||
* re-read.
|
||||
*/
|
||||
while (!done) {
|
||||
status = proc_pending_irqs(dev, &done);
|
||||
if (status)
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int ath6kldev_enable_intrs(struct ath6kl_device *dev)
|
||||
{
|
||||
struct ath6kl_irq_enable_reg regs;
|
||||
int status;
|
||||
|
||||
spin_lock_bh(&dev->lock);
|
||||
|
||||
/* Enable all but ATH6KL CPU interrupts */
|
||||
dev->irq_en_reg.int_status_en =
|
||||
SM(INT_STATUS_ENABLE_ERROR, 0x01) |
|
||||
SM(INT_STATUS_ENABLE_CPU, 0x01) |
|
||||
SM(INT_STATUS_ENABLE_COUNTER, 0x01);
|
||||
|
||||
/*
|
||||
* NOTE: There are some cases where HIF can do detection of
|
||||
* pending mbox messages which is disabled now.
|
||||
*/
|
||||
dev->irq_en_reg.int_status_en |= SM(INT_STATUS_ENABLE_MBOX_DATA, 0x01);
|
||||
|
||||
/* Set up the CPU Interrupt status Register */
|
||||
dev->irq_en_reg.cpu_int_status_en = 0;
|
||||
|
||||
/* Set up the Error Interrupt status Register */
|
||||
dev->irq_en_reg.err_int_status_en =
|
||||
SM(ERROR_STATUS_ENABLE_RX_UNDERFLOW, 0x01) |
|
||||
SM(ERROR_STATUS_ENABLE_TX_OVERFLOW, 0x1);
|
||||
|
||||
/*
|
||||
* Enable Counter interrupt status register to get fatal errors for
|
||||
* debugging.
|
||||
*/
|
||||
dev->irq_en_reg.cntr_int_status_en = SM(COUNTER_INT_STATUS_ENABLE_BIT,
|
||||
ATH6KL_TARGET_DEBUG_INTR_MASK);
|
||||
memcpy(®s, &dev->irq_en_reg, sizeof(regs));
|
||||
|
||||
spin_unlock_bh(&dev->lock);
|
||||
|
||||
status = hif_read_write_sync(dev->ar, INT_STATUS_ENABLE_ADDRESS,
|
||||
®s.int_status_en, sizeof(regs),
|
||||
HIF_WR_SYNC_BYTE_INC);
|
||||
|
||||
if (status)
|
||||
ath6kl_err("failed to update interrupt ctl reg err: %d\n",
|
||||
status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int ath6kldev_disable_intrs(struct ath6kl_device *dev)
|
||||
{
|
||||
struct ath6kl_irq_enable_reg regs;
|
||||
|
||||
spin_lock_bh(&dev->lock);
|
||||
/* Disable all interrupts */
|
||||
dev->irq_en_reg.int_status_en = 0;
|
||||
dev->irq_en_reg.cpu_int_status_en = 0;
|
||||
dev->irq_en_reg.err_int_status_en = 0;
|
||||
dev->irq_en_reg.cntr_int_status_en = 0;
|
||||
memcpy(®s, &dev->irq_en_reg, sizeof(regs));
|
||||
spin_unlock_bh(&dev->lock);
|
||||
|
||||
return hif_read_write_sync(dev->ar, INT_STATUS_ENABLE_ADDRESS,
|
||||
®s.int_status_en, sizeof(regs),
|
||||
HIF_WR_SYNC_BYTE_INC);
|
||||
}
|
||||
|
||||
/* enable device interrupts */
|
||||
int ath6kldev_unmask_intrs(struct ath6kl_device *dev)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
/*
|
||||
* Make sure interrupt are disabled before unmasking at the HIF
|
||||
* layer. The rationale here is that between device insertion
|
||||
* (where we clear the interrupts the first time) and when HTC
|
||||
* is finally ready to handle interrupts, other software can perform
|
||||
* target "soft" resets. The ATH6KL interrupt enables reset back to an
|
||||
* "enabled" state when this happens.
|
||||
*/
|
||||
ath6kldev_disable_intrs(dev);
|
||||
|
||||
/* unmask the host controller interrupts */
|
||||
ath6kl_hif_irq_enable(dev->ar);
|
||||
status = ath6kldev_enable_intrs(dev);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* disable all device interrupts */
|
||||
int ath6kldev_mask_intrs(struct ath6kl_device *dev)
|
||||
{
|
||||
/*
|
||||
* Mask the interrupt at the HIF layer to avoid any stray interrupt
|
||||
* taken while we zero out our shadow registers in
|
||||
* ath6kldev_disable_intrs().
|
||||
*/
|
||||
ath6kl_hif_irq_disable(dev->ar);
|
||||
|
||||
return ath6kldev_disable_intrs(dev);
|
||||
}
|
||||
|
||||
int ath6kldev_setup(struct ath6kl_device *dev)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
spin_lock_init(&dev->lock);
|
||||
|
||||
/*
|
||||
* NOTE: we actually get the block size of a mailbox other than 0,
|
||||
* for SDIO the block size on mailbox 0 is artificially set to 1.
|
||||
* So we use the block size that is set for the other 3 mailboxes.
|
||||
*/
|
||||
dev->htc_cnxt->block_sz = dev->ar->mbox_info.block_size;
|
||||
|
||||
/* must be a power of 2 */
|
||||
if ((dev->htc_cnxt->block_sz & (dev->htc_cnxt->block_sz - 1)) != 0) {
|
||||
WARN_ON(1);
|
||||
goto fail_setup;
|
||||
}
|
||||
|
||||
/* assemble mask, used for padding to a block */
|
||||
dev->htc_cnxt->block_mask = dev->htc_cnxt->block_sz - 1;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_TRC, "block size: %d, mbox addr:0x%X\n",
|
||||
dev->htc_cnxt->block_sz, dev->ar->mbox_info.htc_addr);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_TRC,
|
||||
"hif interrupt processing is sync only\n");
|
||||
|
||||
status = ath6kldev_disable_intrs(dev);
|
||||
|
||||
fail_setup:
|
||||
return status;
|
||||
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright (c) 2007-2011 Atheros Communications 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 HTC_HIF_H
|
||||
#define HTC_HIF_H
|
||||
|
||||
#include "htc.h"
|
||||
#include "hif.h"
|
||||
|
||||
#define ATH6KL_MAILBOXES 4
|
||||
|
||||
/* HTC runs over mailbox 0 */
|
||||
#define HTC_MAILBOX 0
|
||||
|
||||
#define ATH6KL_TARGET_DEBUG_INTR_MASK 0x01
|
||||
|
||||
#define OTHER_INTS_ENABLED (INT_STATUS_ENABLE_ERROR_MASK | \
|
||||
INT_STATUS_ENABLE_CPU_MASK | \
|
||||
INT_STATUS_ENABLE_COUNTER_MASK)
|
||||
|
||||
#define ATH6KL_REG_IO_BUFFER_SIZE 32
|
||||
#define ATH6KL_MAX_REG_IO_BUFFERS 8
|
||||
#define ATH6KL_SCATTER_ENTRIES_PER_REQ 16
|
||||
#define ATH6KL_MAX_TRANSFER_SIZE_PER_SCATTER (16 * 1024)
|
||||
#define ATH6KL_SCATTER_REQS 4
|
||||
|
||||
#ifndef A_CACHE_LINE_PAD
|
||||
#define A_CACHE_LINE_PAD 128
|
||||
#endif
|
||||
#define ATH6KL_MIN_SCATTER_ENTRIES_PER_REQ 2
|
||||
#define ATH6KL_MIN_TRANSFER_SIZE_PER_SCATTER (4 * 1024)
|
||||
|
||||
struct ath6kl_irq_proc_registers {
|
||||
u8 host_int_status;
|
||||
u8 cpu_int_status;
|
||||
u8 error_int_status;
|
||||
u8 counter_int_status;
|
||||
u8 mbox_frame;
|
||||
u8 rx_lkahd_valid;
|
||||
u8 host_int_status2;
|
||||
u8 gmbox_rx_avail;
|
||||
__le32 rx_lkahd[2];
|
||||
__le32 rx_gmbox_lkahd_alias[2];
|
||||
} __packed;
|
||||
|
||||
struct ath6kl_irq_enable_reg {
|
||||
u8 int_status_en;
|
||||
u8 cpu_int_status_en;
|
||||
u8 err_int_status_en;
|
||||
u8 cntr_int_status_en;
|
||||
} __packed;
|
||||
|
||||
struct ath6kl_device {
|
||||
spinlock_t lock;
|
||||
u8 pad1[A_CACHE_LINE_PAD];
|
||||
struct ath6kl_irq_proc_registers irq_proc_reg;
|
||||
u8 pad2[A_CACHE_LINE_PAD];
|
||||
struct ath6kl_irq_enable_reg irq_en_reg;
|
||||
u8 pad3[A_CACHE_LINE_PAD];
|
||||
struct htc_target *htc_cnxt;
|
||||
struct ath6kl *ar;
|
||||
};
|
||||
|
||||
int ath6kldev_setup(struct ath6kl_device *dev);
|
||||
int ath6kldev_unmask_intrs(struct ath6kl_device *dev);
|
||||
int ath6kldev_mask_intrs(struct ath6kl_device *dev);
|
||||
int ath6kldev_poll_mboxmsg_rx(struct ath6kl_device *dev,
|
||||
u32 *lk_ahd, int timeout);
|
||||
int ath6kldev_rx_control(struct ath6kl_device *dev, bool enable_rx);
|
||||
int ath6kldev_disable_intrs(struct ath6kl_device *dev);
|
||||
|
||||
int ath6kldev_rw_comp_handler(void *context, int status);
|
||||
int ath6kldev_intr_bh_handler(struct ath6kl *ar);
|
||||
|
||||
/* Scatter Function and Definitions */
|
||||
int ath6kldev_submit_scat_req(struct ath6kl_device *dev,
|
||||
struct hif_scatter_req *scat_req, bool read);
|
||||
|
||||
#endif /*ATH6KL_H_ */
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2011 Atheros Communications 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 "htc.h"
|
||||
#include "wmi.h"
|
||||
#include "debug.h"
|
||||
|
||||
struct bss *wlan_node_alloc(int wh_size)
|
||||
{
|
||||
struct bss *ni;
|
||||
|
||||
ni = kzalloc(sizeof(struct bss), GFP_ATOMIC);
|
||||
|
||||
if ((ni != NULL) && wh_size) {
|
||||
ni->ni_buf = kmalloc(wh_size, GFP_ATOMIC);
|
||||
if (ni->ni_buf == NULL) {
|
||||
kfree(ni);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return ni;
|
||||
}
|
||||
|
||||
void wlan_node_free(struct bss *ni)
|
||||
{
|
||||
kfree(ni->ni_buf);
|
||||
kfree(ni);
|
||||
}
|
||||
|
||||
void wlan_setup_node(struct ath6kl_node_table *nt, struct bss *ni,
|
||||
const u8 *mac_addr)
|
||||
{
|
||||
int hash;
|
||||
|
||||
memcpy(ni->ni_macaddr, mac_addr, ETH_ALEN);
|
||||
hash = ATH6KL_NODE_HASH(mac_addr);
|
||||
ni->ni_refcnt = 1;
|
||||
|
||||
ni->ni_tstamp = jiffies_to_msecs(jiffies);
|
||||
ni->ni_actcnt = WLAN_NODE_INACT_CNT;
|
||||
|
||||
spin_lock_bh(&nt->nt_nodelock);
|
||||
|
||||
/* insert at the end of the node list */
|
||||
ni->ni_list_next = NULL;
|
||||
ni->ni_list_prev = nt->nt_node_last;
|
||||
if (nt->nt_node_last != NULL)
|
||||
nt->nt_node_last->ni_list_next = ni;
|
||||
|
||||
nt->nt_node_last = ni;
|
||||
if (nt->nt_node_first == NULL)
|
||||
nt->nt_node_first = ni;
|
||||
|
||||
/* insert into the hash list */
|
||||
ni->ni_hash_next = nt->nt_hash[hash];
|
||||
if (ni->ni_hash_next != NULL)
|
||||
nt->nt_hash[hash]->ni_hash_prev = ni;
|
||||
|
||||
ni->ni_hash_prev = NULL;
|
||||
nt->nt_hash[hash] = ni;
|
||||
|
||||
spin_unlock_bh(&nt->nt_nodelock);
|
||||
}
|
||||
|
||||
struct bss *wlan_find_node(struct ath6kl_node_table *nt,
|
||||
const u8 *mac_addr)
|
||||
{
|
||||
struct bss *ni, *found_ni = NULL;
|
||||
int hash;
|
||||
|
||||
spin_lock_bh(&nt->nt_nodelock);
|
||||
|
||||
hash = ATH6KL_NODE_HASH(mac_addr);
|
||||
for (ni = nt->nt_hash[hash]; ni; ni = ni->ni_hash_next) {
|
||||
if (memcmp(ni->ni_macaddr, mac_addr, ETH_ALEN) == 0) {
|
||||
ni->ni_refcnt++;
|
||||
found_ni = ni;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_bh(&nt->nt_nodelock);
|
||||
|
||||
return found_ni;
|
||||
}
|
||||
|
||||
void wlan_node_reclaim(struct ath6kl_node_table *nt, struct bss *ni)
|
||||
{
|
||||
int hash;
|
||||
|
||||
spin_lock_bh(&nt->nt_nodelock);
|
||||
|
||||
if (ni->ni_list_prev == NULL)
|
||||
/* fix list head */
|
||||
nt->nt_node_first = ni->ni_list_next;
|
||||
else
|
||||
ni->ni_list_prev->ni_list_next = ni->ni_list_next;
|
||||
|
||||
if (ni->ni_list_next == NULL)
|
||||
/* fix list tail */
|
||||
nt->nt_node_last = ni->ni_list_prev;
|
||||
else
|
||||
ni->ni_list_next->ni_list_prev = ni->ni_list_prev;
|
||||
|
||||
if (ni->ni_hash_prev == NULL) {
|
||||
/* first in list so fix the list head */
|
||||
hash = ATH6KL_NODE_HASH(ni->ni_macaddr);
|
||||
nt->nt_hash[hash] = ni->ni_hash_next;
|
||||
} else {
|
||||
ni->ni_hash_prev->ni_hash_next = ni->ni_hash_next;
|
||||
}
|
||||
|
||||
if (ni->ni_hash_next != NULL)
|
||||
ni->ni_hash_next->ni_hash_prev = ni->ni_hash_prev;
|
||||
|
||||
wlan_node_free(ni);
|
||||
|
||||
spin_unlock_bh(&nt->nt_nodelock);
|
||||
}
|
||||
|
||||
static void wlan_node_dec_free(struct bss *ni)
|
||||
{
|
||||
if ((ni->ni_refcnt--) == 1)
|
||||
wlan_node_free(ni);
|
||||
}
|
||||
|
||||
void wlan_free_allnodes(struct ath6kl_node_table *nt)
|
||||
{
|
||||
struct bss *ni;
|
||||
|
||||
while ((ni = nt->nt_node_first) != NULL)
|
||||
wlan_node_reclaim(nt, ni);
|
||||
}
|
||||
|
||||
void wlan_iterate_nodes(struct ath6kl_node_table *nt, void *arg)
|
||||
{
|
||||
struct bss *ni;
|
||||
|
||||
spin_lock_bh(&nt->nt_nodelock);
|
||||
for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) {
|
||||
ni->ni_refcnt++;
|
||||
ath6kl_cfg80211_scan_node(arg, ni);
|
||||
wlan_node_dec_free(ni);
|
||||
}
|
||||
spin_unlock_bh(&nt->nt_nodelock);
|
||||
}
|
||||
|
||||
void wlan_node_table_init(struct ath6kl_node_table *nt)
|
||||
{
|
||||
ath6kl_dbg(ATH6KL_DBG_WLAN_NODE, "node table = 0x%lx\n",
|
||||
(unsigned long)nt);
|
||||
|
||||
memset(nt, 0, sizeof(struct ath6kl_node_table));
|
||||
|
||||
spin_lock_init(&nt->nt_nodelock);
|
||||
|
||||
nt->nt_node_age = WLAN_NODE_INACT_TIMEOUT_MSEC;
|
||||
}
|
||||
|
||||
void wlan_refresh_inactive_nodes(struct ath6kl *ar)
|
||||
{
|
||||
struct ath6kl_node_table *nt = &ar->scan_table;
|
||||
struct bss *bss;
|
||||
u32 now;
|
||||
|
||||
now = jiffies_to_msecs(jiffies);
|
||||
bss = nt->nt_node_first;
|
||||
while (bss != NULL) {
|
||||
/* refresh all nodes except the current bss */
|
||||
if (memcmp(ar->bssid, bss->ni_macaddr, ETH_ALEN) != 0) {
|
||||
if (((now - bss->ni_tstamp) > nt->nt_node_age)
|
||||
|| --bss->ni_actcnt == 0) {
|
||||
wlan_node_reclaim(nt, bss);
|
||||
}
|
||||
}
|
||||
bss = bss->ni_list_next;
|
||||
}
|
||||
}
|
||||
|
||||
void wlan_node_table_cleanup(struct ath6kl_node_table *nt)
|
||||
{
|
||||
wlan_free_allnodes(nt);
|
||||
}
|
||||
|
||||
struct bss *wlan_find_ssid_node(struct ath6kl_node_table *nt, u8 * ssid,
|
||||
u32 ssid_len, bool is_wpa2, bool match_ssid)
|
||||
{
|
||||
struct bss *ni, *found_ni = NULL;
|
||||
u8 *ie_ssid;
|
||||
|
||||
spin_lock_bh(&nt->nt_nodelock);
|
||||
|
||||
for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) {
|
||||
|
||||
ie_ssid = ni->ni_cie.ie_ssid;
|
||||
|
||||
if ((ie_ssid[1] <= IEEE80211_MAX_SSID_LEN) &&
|
||||
(memcmp(ssid, &ie_ssid[2], ssid_len) == 0)) {
|
||||
|
||||
if (match_ssid ||
|
||||
(is_wpa2 && ni->ni_cie.ie_rsn != NULL) ||
|
||||
(!is_wpa2 && ni->ni_cie.ie_wpa != NULL)) {
|
||||
ni->ni_refcnt++;
|
||||
found_ni = ni;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_bh(&nt->nt_nodelock);
|
||||
|
||||
return found_ni;
|
||||
}
|
||||
|
||||
void wlan_node_return(struct ath6kl_node_table *nt, struct bss *ni)
|
||||
{
|
||||
spin_lock_bh(&nt->nt_nodelock);
|
||||
wlan_node_dec_free(ni);
|
||||
spin_unlock_bh(&nt->nt_nodelock);
|
||||
}
|
|
@ -0,0 +1,912 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2011 Atheros Communications 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/mmc/card.h>
|
||||
#include <linux/mmc/mmc.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/mmc/sdio_func.h>
|
||||
#include <linux/mmc/sdio_ids.h>
|
||||
#include <linux/mmc/sdio.h>
|
||||
#include <linux/mmc/sd.h>
|
||||
#include "htc_hif.h"
|
||||
#include "hif-ops.h"
|
||||
#include "target.h"
|
||||
#include "debug.h"
|
||||
|
||||
struct ath6kl_sdio {
|
||||
struct sdio_func *func;
|
||||
|
||||
spinlock_t lock;
|
||||
|
||||
/* free list */
|
||||
struct list_head bus_req_freeq;
|
||||
|
||||
/* available bus requests */
|
||||
struct bus_request bus_req[BUS_REQUEST_MAX_NUM];
|
||||
|
||||
struct ath6kl *ar;
|
||||
u8 *dma_buffer;
|
||||
|
||||
/* scatter request list head */
|
||||
struct list_head scat_req;
|
||||
|
||||
spinlock_t scat_lock;
|
||||
bool is_disabled;
|
||||
atomic_t irq_handling;
|
||||
const struct sdio_device_id *id;
|
||||
struct work_struct wr_async_work;
|
||||
struct list_head wr_asyncq;
|
||||
spinlock_t wr_async_lock;
|
||||
};
|
||||
|
||||
#define CMD53_ARG_READ 0
|
||||
#define CMD53_ARG_WRITE 1
|
||||
#define CMD53_ARG_BLOCK_BASIS 1
|
||||
#define CMD53_ARG_FIXED_ADDRESS 0
|
||||
#define CMD53_ARG_INCR_ADDRESS 1
|
||||
|
||||
static inline struct ath6kl_sdio *ath6kl_sdio_priv(struct ath6kl *ar)
|
||||
{
|
||||
return ar->hif_priv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Macro to check if DMA buffer is WORD-aligned and DMA-able.
|
||||
* Most host controllers assume the buffer is DMA'able and will
|
||||
* bug-check otherwise (i.e. buffers on the stack). virt_addr_valid
|
||||
* check fails on stack memory.
|
||||
*/
|
||||
static inline bool buf_needs_bounce(u8 *buf)
|
||||
{
|
||||
return ((unsigned long) buf & 0x3) || !virt_addr_valid(buf);
|
||||
}
|
||||
|
||||
static void ath6kl_sdio_set_mbox_info(struct ath6kl *ar)
|
||||
{
|
||||
struct ath6kl_mbox_info *mbox_info = &ar->mbox_info;
|
||||
|
||||
/* EP1 has an extended range */
|
||||
mbox_info->htc_addr = HIF_MBOX_BASE_ADDR;
|
||||
mbox_info->htc_ext_addr = HIF_MBOX0_EXT_BASE_ADDR;
|
||||
mbox_info->htc_ext_sz = HIF_MBOX0_EXT_WIDTH;
|
||||
mbox_info->block_size = HIF_MBOX_BLOCK_SIZE;
|
||||
mbox_info->gmbox_addr = HIF_GMBOX_BASE_ADDR;
|
||||
mbox_info->gmbox_sz = HIF_GMBOX_WIDTH;
|
||||
}
|
||||
|
||||
static inline void ath6kl_sdio_set_cmd53_arg(u32 *arg, u8 rw, u8 func,
|
||||
u8 mode, u8 opcode, u32 addr,
|
||||
u16 blksz)
|
||||
{
|
||||
*arg = (((rw & 1) << 31) |
|
||||
((func & 0x7) << 28) |
|
||||
((mode & 1) << 27) |
|
||||
((opcode & 1) << 26) |
|
||||
((addr & 0x1FFFF) << 9) |
|
||||
(blksz & 0x1FF));
|
||||
}
|
||||
|
||||
static inline void ath6kl_sdio_set_cmd52_arg(u32 *arg, u8 write, u8 raw,
|
||||
unsigned int address,
|
||||
unsigned char val)
|
||||
{
|
||||
const u8 func = 0;
|
||||
|
||||
*arg = ((write & 1) << 31) |
|
||||
((func & 0x7) << 28) |
|
||||
((raw & 1) << 27) |
|
||||
(1 << 26) |
|
||||
((address & 0x1FFFF) << 9) |
|
||||
(1 << 8) |
|
||||
(val & 0xFF);
|
||||
}
|
||||
|
||||
static int ath6kl_sdio_func0_cmd52_wr_byte(struct mmc_card *card,
|
||||
unsigned int address,
|
||||
unsigned char byte)
|
||||
{
|
||||
struct mmc_command io_cmd;
|
||||
|
||||
memset(&io_cmd, 0, sizeof(io_cmd));
|
||||
ath6kl_sdio_set_cmd52_arg(&io_cmd.arg, 1, 0, address, byte);
|
||||
io_cmd.opcode = SD_IO_RW_DIRECT;
|
||||
io_cmd.flags = MMC_RSP_R5 | MMC_CMD_AC;
|
||||
|
||||
return mmc_wait_for_cmd(card->host, &io_cmd, 0);
|
||||
}
|
||||
|
||||
static int ath6kl_sdio_io(struct sdio_func *func, u32 request, u32 addr,
|
||||
u8 *buf, u32 len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (request & HIF_WRITE) {
|
||||
if (addr >= HIF_MBOX_BASE_ADDR &&
|
||||
addr <= HIF_MBOX_END_ADDR)
|
||||
addr += (HIF_MBOX_WIDTH - len);
|
||||
|
||||
if (addr == HIF_MBOX0_EXT_BASE_ADDR)
|
||||
addr += HIF_MBOX0_EXT_WIDTH - len;
|
||||
|
||||
if (request & HIF_FIXED_ADDRESS)
|
||||
ret = sdio_writesb(func, addr, buf, len);
|
||||
else
|
||||
ret = sdio_memcpy_toio(func, addr, buf, len);
|
||||
} else {
|
||||
if (request & HIF_FIXED_ADDRESS)
|
||||
ret = sdio_readsb(func, buf, addr, len);
|
||||
else
|
||||
ret = sdio_memcpy_fromio(func, buf, addr, len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct bus_request *ath6kl_sdio_alloc_busreq(struct ath6kl_sdio *ar_sdio)
|
||||
{
|
||||
struct bus_request *bus_req;
|
||||
unsigned long flag;
|
||||
|
||||
spin_lock_irqsave(&ar_sdio->lock, flag);
|
||||
|
||||
if (list_empty(&ar_sdio->bus_req_freeq)) {
|
||||
spin_unlock_irqrestore(&ar_sdio->lock, flag);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bus_req = list_first_entry(&ar_sdio->bus_req_freeq,
|
||||
struct bus_request, list);
|
||||
list_del(&bus_req->list);
|
||||
|
||||
spin_unlock_irqrestore(&ar_sdio->lock, flag);
|
||||
ath6kl_dbg(ATH6KL_DBG_TRC, "%s: bus request 0x%p\n", __func__, bus_req);
|
||||
|
||||
return bus_req;
|
||||
}
|
||||
|
||||
static void ath6kl_sdio_free_bus_req(struct ath6kl_sdio *ar_sdio,
|
||||
struct bus_request *bus_req)
|
||||
{
|
||||
unsigned long flag;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_TRC, "%s: bus request 0x%p\n", __func__, bus_req);
|
||||
|
||||
spin_lock_irqsave(&ar_sdio->lock, flag);
|
||||
list_add_tail(&bus_req->list, &ar_sdio->bus_req_freeq);
|
||||
spin_unlock_irqrestore(&ar_sdio->lock, flag);
|
||||
}
|
||||
|
||||
static void ath6kl_sdio_setup_scat_data(struct hif_scatter_req *scat_req,
|
||||
struct mmc_data *data)
|
||||
{
|
||||
struct scatterlist *sg;
|
||||
int i;
|
||||
|
||||
data->blksz = HIF_MBOX_BLOCK_SIZE;
|
||||
data->blocks = scat_req->len / HIF_MBOX_BLOCK_SIZE;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_SCATTER,
|
||||
"hif-scatter: (%s) addr: 0x%X, (block len: %d, block count: %d) , (tot:%d,sg:%d)\n",
|
||||
(scat_req->req & HIF_WRITE) ? "WR" : "RD", scat_req->addr,
|
||||
data->blksz, data->blocks, scat_req->len,
|
||||
scat_req->scat_entries);
|
||||
|
||||
data->flags = (scat_req->req & HIF_WRITE) ? MMC_DATA_WRITE :
|
||||
MMC_DATA_READ;
|
||||
|
||||
/* fill SG entries */
|
||||
sg = scat_req->sgentries;
|
||||
sg_init_table(sg, scat_req->scat_entries);
|
||||
|
||||
/* assemble SG list */
|
||||
for (i = 0; i < scat_req->scat_entries; i++, sg++) {
|
||||
if ((unsigned long)scat_req->scat_list[i].buf & 0x3)
|
||||
/*
|
||||
* Some scatter engines can handle unaligned
|
||||
* buffers, print this as informational only.
|
||||
*/
|
||||
ath6kl_dbg(ATH6KL_DBG_SCATTER,
|
||||
"(%s) scatter buffer is unaligned 0x%p\n",
|
||||
scat_req->req & HIF_WRITE ? "WR" : "RD",
|
||||
scat_req->scat_list[i].buf);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_SCATTER, "%d: addr:0x%p, len:%d\n",
|
||||
i, scat_req->scat_list[i].buf,
|
||||
scat_req->scat_list[i].len);
|
||||
|
||||
sg_set_buf(sg, scat_req->scat_list[i].buf,
|
||||
scat_req->scat_list[i].len);
|
||||
}
|
||||
|
||||
/* set scatter-gather table for request */
|
||||
data->sg = scat_req->sgentries;
|
||||
data->sg_len = scat_req->scat_entries;
|
||||
}
|
||||
|
||||
static int ath6kl_sdio_scat_rw(struct ath6kl_sdio *ar_sdio,
|
||||
struct bus_request *req)
|
||||
{
|
||||
struct mmc_request mmc_req;
|
||||
struct mmc_command cmd;
|
||||
struct mmc_data data;
|
||||
struct hif_scatter_req *scat_req;
|
||||
u8 opcode, rw;
|
||||
int status, len;
|
||||
|
||||
scat_req = req->scat_req;
|
||||
|
||||
if (scat_req->virt_scat) {
|
||||
len = scat_req->len;
|
||||
if (scat_req->req & HIF_BLOCK_BASIS)
|
||||
len = round_down(len, HIF_MBOX_BLOCK_SIZE);
|
||||
|
||||
status = ath6kl_sdio_io(ar_sdio->func, scat_req->req,
|
||||
scat_req->addr, scat_req->virt_dma_buf,
|
||||
len);
|
||||
goto scat_complete;
|
||||
}
|
||||
|
||||
memset(&mmc_req, 0, sizeof(struct mmc_request));
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
memset(&data, 0, sizeof(struct mmc_data));
|
||||
|
||||
ath6kl_sdio_setup_scat_data(scat_req, &data);
|
||||
|
||||
opcode = (scat_req->req & HIF_FIXED_ADDRESS) ?
|
||||
CMD53_ARG_FIXED_ADDRESS : CMD53_ARG_INCR_ADDRESS;
|
||||
|
||||
rw = (scat_req->req & HIF_WRITE) ? CMD53_ARG_WRITE : CMD53_ARG_READ;
|
||||
|
||||
/* Fixup the address so that the last byte will fall on MBOX EOM */
|
||||
if (scat_req->req & HIF_WRITE) {
|
||||
if (scat_req->addr == HIF_MBOX_BASE_ADDR)
|
||||
scat_req->addr += HIF_MBOX_WIDTH - scat_req->len;
|
||||
else
|
||||
/* Uses extended address range */
|
||||
scat_req->addr += HIF_MBOX0_EXT_WIDTH - scat_req->len;
|
||||
}
|
||||
|
||||
/* set command argument */
|
||||
ath6kl_sdio_set_cmd53_arg(&cmd.arg, rw, ar_sdio->func->num,
|
||||
CMD53_ARG_BLOCK_BASIS, opcode, scat_req->addr,
|
||||
data.blocks);
|
||||
|
||||
cmd.opcode = SD_IO_RW_EXTENDED;
|
||||
cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
|
||||
|
||||
mmc_req.cmd = &cmd;
|
||||
mmc_req.data = &data;
|
||||
|
||||
mmc_set_data_timeout(&data, ar_sdio->func->card);
|
||||
/* synchronous call to process request */
|
||||
mmc_wait_for_req(ar_sdio->func->card->host, &mmc_req);
|
||||
|
||||
status = cmd.error ? cmd.error : data.error;
|
||||
|
||||
scat_complete:
|
||||
scat_req->status = status;
|
||||
|
||||
if (scat_req->status)
|
||||
ath6kl_err("Scatter write request failed:%d\n",
|
||||
scat_req->status);
|
||||
|
||||
if (scat_req->req & HIF_ASYNCHRONOUS)
|
||||
scat_req->complete(ar_sdio->ar->htc_target, scat_req);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int ath6kl_sdio_alloc_prep_scat_req(struct ath6kl_sdio *ar_sdio,
|
||||
int n_scat_entry, int n_scat_req,
|
||||
bool virt_scat)
|
||||
{
|
||||
struct hif_scatter_req *s_req;
|
||||
struct bus_request *bus_req;
|
||||
int i, scat_req_sz, scat_list_sz, sg_sz, buf_sz;
|
||||
u8 *virt_buf;
|
||||
|
||||
scat_list_sz = (n_scat_entry - 1) * sizeof(struct hif_scatter_item);
|
||||
scat_req_sz = sizeof(*s_req) + scat_list_sz;
|
||||
|
||||
if (!virt_scat)
|
||||
sg_sz = sizeof(struct scatterlist) * n_scat_entry;
|
||||
else
|
||||
buf_sz = 2 * L1_CACHE_BYTES +
|
||||
ATH6KL_MAX_TRANSFER_SIZE_PER_SCATTER;
|
||||
|
||||
for (i = 0; i < n_scat_req; i++) {
|
||||
/* allocate the scatter request */
|
||||
s_req = kzalloc(scat_req_sz, GFP_KERNEL);
|
||||
if (!s_req)
|
||||
return -ENOMEM;
|
||||
|
||||
if (virt_scat) {
|
||||
virt_buf = kzalloc(buf_sz, GFP_KERNEL);
|
||||
if (!virt_buf) {
|
||||
kfree(s_req);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
s_req->virt_dma_buf =
|
||||
(u8 *)L1_CACHE_ALIGN((unsigned long)virt_buf);
|
||||
} else {
|
||||
/* allocate sglist */
|
||||
s_req->sgentries = kzalloc(sg_sz, GFP_KERNEL);
|
||||
|
||||
if (!s_req->sgentries) {
|
||||
kfree(s_req);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
/* allocate a bus request for this scatter request */
|
||||
bus_req = ath6kl_sdio_alloc_busreq(ar_sdio);
|
||||
if (!bus_req) {
|
||||
kfree(s_req->sgentries);
|
||||
kfree(s_req->virt_dma_buf);
|
||||
kfree(s_req);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* assign the scatter request to this bus request */
|
||||
bus_req->scat_req = s_req;
|
||||
s_req->busrequest = bus_req;
|
||||
|
||||
s_req->virt_scat = virt_scat;
|
||||
|
||||
/* add it to the scatter pool */
|
||||
hif_scatter_req_add(ar_sdio->ar, s_req);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kl_sdio_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf,
|
||||
u32 len, u32 request)
|
||||
{
|
||||
struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
|
||||
u8 *tbuf = NULL;
|
||||
int ret;
|
||||
bool bounced = false;
|
||||
|
||||
if (request & HIF_BLOCK_BASIS)
|
||||
len = round_down(len, HIF_MBOX_BLOCK_SIZE);
|
||||
|
||||
if (buf_needs_bounce(buf)) {
|
||||
if (!ar_sdio->dma_buffer)
|
||||
return -ENOMEM;
|
||||
tbuf = ar_sdio->dma_buffer;
|
||||
memcpy(tbuf, buf, len);
|
||||
bounced = true;
|
||||
} else
|
||||
tbuf = buf;
|
||||
|
||||
sdio_claim_host(ar_sdio->func);
|
||||
ret = ath6kl_sdio_io(ar_sdio->func, request, addr, tbuf, len);
|
||||
if ((request & HIF_READ) && bounced)
|
||||
memcpy(buf, tbuf, len);
|
||||
sdio_release_host(ar_sdio->func);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __ath6kl_sdio_write_async(struct ath6kl_sdio *ar_sdio,
|
||||
struct bus_request *req)
|
||||
{
|
||||
if (req->scat_req)
|
||||
ath6kl_sdio_scat_rw(ar_sdio, req);
|
||||
else {
|
||||
void *context;
|
||||
int status;
|
||||
|
||||
status = ath6kl_sdio_read_write_sync(ar_sdio->ar, req->address,
|
||||
req->buffer, req->length,
|
||||
req->request);
|
||||
context = req->packet;
|
||||
ath6kl_sdio_free_bus_req(ar_sdio, req);
|
||||
ath6kldev_rw_comp_handler(context, status);
|
||||
}
|
||||
}
|
||||
|
||||
static void ath6kl_sdio_write_async_work(struct work_struct *work)
|
||||
{
|
||||
struct ath6kl_sdio *ar_sdio;
|
||||
unsigned long flags;
|
||||
struct bus_request *req, *tmp_req;
|
||||
|
||||
ar_sdio = container_of(work, struct ath6kl_sdio, wr_async_work);
|
||||
sdio_claim_host(ar_sdio->func);
|
||||
|
||||
spin_lock_irqsave(&ar_sdio->wr_async_lock, flags);
|
||||
list_for_each_entry_safe(req, tmp_req, &ar_sdio->wr_asyncq, list) {
|
||||
list_del(&req->list);
|
||||
spin_unlock_irqrestore(&ar_sdio->wr_async_lock, flags);
|
||||
__ath6kl_sdio_write_async(ar_sdio, req);
|
||||
spin_lock_irqsave(&ar_sdio->wr_async_lock, flags);
|
||||
}
|
||||
spin_unlock_irqrestore(&ar_sdio->wr_async_lock, flags);
|
||||
|
||||
sdio_release_host(ar_sdio->func);
|
||||
}
|
||||
|
||||
static void ath6kl_sdio_irq_handler(struct sdio_func *func)
|
||||
{
|
||||
int status;
|
||||
struct ath6kl_sdio *ar_sdio;
|
||||
|
||||
ar_sdio = sdio_get_drvdata(func);
|
||||
atomic_set(&ar_sdio->irq_handling, 1);
|
||||
|
||||
/*
|
||||
* Release the host during interrups so we can pick it back up when
|
||||
* we process commands.
|
||||
*/
|
||||
sdio_release_host(ar_sdio->func);
|
||||
|
||||
status = ath6kldev_intr_bh_handler(ar_sdio->ar);
|
||||
sdio_claim_host(ar_sdio->func);
|
||||
atomic_set(&ar_sdio->irq_handling, 0);
|
||||
WARN_ON(status && status != -ECANCELED);
|
||||
}
|
||||
|
||||
static int ath6kl_sdio_power_on(struct ath6kl_sdio *ar_sdio)
|
||||
{
|
||||
struct sdio_func *func = ar_sdio->func;
|
||||
int ret = 0;
|
||||
|
||||
if (!ar_sdio->is_disabled)
|
||||
return 0;
|
||||
|
||||
sdio_claim_host(func);
|
||||
|
||||
ret = sdio_enable_func(func);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to enable sdio func: %d)\n", ret);
|
||||
sdio_release_host(func);
|
||||
return ret;
|
||||
}
|
||||
|
||||
sdio_release_host(func);
|
||||
|
||||
/*
|
||||
* Wait for hardware to initialise. It should take a lot less than
|
||||
* 10 ms but let's be conservative here.
|
||||
*/
|
||||
msleep(10);
|
||||
|
||||
ar_sdio->is_disabled = false;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath6kl_sdio_power_off(struct ath6kl_sdio *ar_sdio)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (ar_sdio->is_disabled)
|
||||
return 0;
|
||||
|
||||
/* Disable the card */
|
||||
sdio_claim_host(ar_sdio->func);
|
||||
ret = sdio_disable_func(ar_sdio->func);
|
||||
sdio_release_host(ar_sdio->func);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ar_sdio->is_disabled = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath6kl_sdio_write_async(struct ath6kl *ar, u32 address, u8 *buffer,
|
||||
u32 length, u32 request,
|
||||
struct htc_packet *packet)
|
||||
{
|
||||
struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
|
||||
struct bus_request *bus_req;
|
||||
unsigned long flags;
|
||||
|
||||
bus_req = ath6kl_sdio_alloc_busreq(ar_sdio);
|
||||
|
||||
if (!bus_req)
|
||||
return -ENOMEM;
|
||||
|
||||
bus_req->address = address;
|
||||
bus_req->buffer = buffer;
|
||||
bus_req->length = length;
|
||||
bus_req->request = request;
|
||||
bus_req->packet = packet;
|
||||
|
||||
spin_lock_irqsave(&ar_sdio->wr_async_lock, flags);
|
||||
list_add_tail(&bus_req->list, &ar_sdio->wr_asyncq);
|
||||
spin_unlock_irqrestore(&ar_sdio->wr_async_lock, flags);
|
||||
queue_work(ar->ath6kl_wq, &ar_sdio->wr_async_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath6kl_sdio_irq_enable(struct ath6kl *ar)
|
||||
{
|
||||
struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
|
||||
int ret;
|
||||
|
||||
sdio_claim_host(ar_sdio->func);
|
||||
|
||||
/* Register the isr */
|
||||
ret = sdio_claim_irq(ar_sdio->func, ath6kl_sdio_irq_handler);
|
||||
if (ret)
|
||||
ath6kl_err("Failed to claim sdio irq: %d\n", ret);
|
||||
|
||||
sdio_release_host(ar_sdio->func);
|
||||
}
|
||||
|
||||
static void ath6kl_sdio_irq_disable(struct ath6kl *ar)
|
||||
{
|
||||
struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
|
||||
int ret;
|
||||
|
||||
sdio_claim_host(ar_sdio->func);
|
||||
|
||||
/* Mask our function IRQ */
|
||||
while (atomic_read(&ar_sdio->irq_handling)) {
|
||||
sdio_release_host(ar_sdio->func);
|
||||
schedule_timeout(HZ / 10);
|
||||
sdio_claim_host(ar_sdio->func);
|
||||
}
|
||||
|
||||
ret = sdio_release_irq(ar_sdio->func);
|
||||
if (ret)
|
||||
ath6kl_err("Failed to release sdio irq: %d\n", ret);
|
||||
|
||||
sdio_release_host(ar_sdio->func);
|
||||
}
|
||||
|
||||
static struct hif_scatter_req *ath6kl_sdio_scatter_req_get(struct ath6kl *ar)
|
||||
{
|
||||
struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
|
||||
struct hif_scatter_req *node = NULL;
|
||||
unsigned long flag;
|
||||
|
||||
spin_lock_irqsave(&ar_sdio->scat_lock, flag);
|
||||
|
||||
if (!list_empty(&ar_sdio->scat_req)) {
|
||||
node = list_first_entry(&ar_sdio->scat_req,
|
||||
struct hif_scatter_req, list);
|
||||
list_del(&node->list);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&ar_sdio->scat_lock, flag);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static void ath6kl_sdio_scatter_req_add(struct ath6kl *ar,
|
||||
struct hif_scatter_req *s_req)
|
||||
{
|
||||
struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
|
||||
unsigned long flag;
|
||||
|
||||
spin_lock_irqsave(&ar_sdio->scat_lock, flag);
|
||||
|
||||
list_add_tail(&s_req->list, &ar_sdio->scat_req);
|
||||
|
||||
spin_unlock_irqrestore(&ar_sdio->scat_lock, flag);
|
||||
|
||||
}
|
||||
|
||||
/* scatter gather read write request */
|
||||
static int ath6kl_sdio_async_rw_scatter(struct ath6kl *ar,
|
||||
struct hif_scatter_req *scat_req)
|
||||
{
|
||||
struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
|
||||
u32 request = scat_req->req;
|
||||
int status = 0;
|
||||
unsigned long flags;
|
||||
|
||||
if (!scat_req->len)
|
||||
return -EINVAL;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_SCATTER,
|
||||
"hif-scatter: total len: %d scatter entries: %d\n",
|
||||
scat_req->len, scat_req->scat_entries);
|
||||
|
||||
if (request & HIF_SYNCHRONOUS) {
|
||||
sdio_claim_host(ar_sdio->func);
|
||||
status = ath6kl_sdio_scat_rw(ar_sdio, scat_req->busrequest);
|
||||
sdio_release_host(ar_sdio->func);
|
||||
} else {
|
||||
spin_lock_irqsave(&ar_sdio->wr_async_lock, flags);
|
||||
list_add_tail(&scat_req->busrequest->list, &ar_sdio->wr_asyncq);
|
||||
spin_unlock_irqrestore(&ar_sdio->wr_async_lock, flags);
|
||||
queue_work(ar->ath6kl_wq, &ar_sdio->wr_async_work);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* clean up scatter support */
|
||||
static void ath6kl_sdio_cleanup_scatter(struct ath6kl *ar)
|
||||
{
|
||||
struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
|
||||
struct hif_scatter_req *s_req, *tmp_req;
|
||||
unsigned long flag;
|
||||
|
||||
/* empty the free list */
|
||||
spin_lock_irqsave(&ar_sdio->scat_lock, flag);
|
||||
list_for_each_entry_safe(s_req, tmp_req, &ar_sdio->scat_req, list) {
|
||||
list_del(&s_req->list);
|
||||
spin_unlock_irqrestore(&ar_sdio->scat_lock, flag);
|
||||
|
||||
if (s_req->busrequest)
|
||||
ath6kl_sdio_free_bus_req(ar_sdio, s_req->busrequest);
|
||||
kfree(s_req->virt_dma_buf);
|
||||
kfree(s_req->sgentries);
|
||||
kfree(s_req);
|
||||
|
||||
spin_lock_irqsave(&ar_sdio->scat_lock, flag);
|
||||
}
|
||||
spin_unlock_irqrestore(&ar_sdio->scat_lock, flag);
|
||||
}
|
||||
|
||||
/* setup of HIF scatter resources */
|
||||
static int ath6kl_sdio_enable_scatter(struct ath6kl *ar)
|
||||
{
|
||||
struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
|
||||
struct htc_target *target = ar->htc_target;
|
||||
int ret;
|
||||
bool virt_scat = false;
|
||||
|
||||
/* check if host supports scatter and it meets our requirements */
|
||||
if (ar_sdio->func->card->host->max_segs < MAX_SCATTER_ENTRIES_PER_REQ) {
|
||||
ath6kl_err("host only supports scatter of :%d entries, need: %d\n",
|
||||
ar_sdio->func->card->host->max_segs,
|
||||
MAX_SCATTER_ENTRIES_PER_REQ);
|
||||
virt_scat = true;
|
||||
}
|
||||
|
||||
if (!virt_scat) {
|
||||
ret = ath6kl_sdio_alloc_prep_scat_req(ar_sdio,
|
||||
MAX_SCATTER_ENTRIES_PER_REQ,
|
||||
MAX_SCATTER_REQUESTS, virt_scat);
|
||||
|
||||
if (!ret) {
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"hif-scatter enabled: max scatter req : %d entries: %d\n",
|
||||
MAX_SCATTER_REQUESTS,
|
||||
MAX_SCATTER_ENTRIES_PER_REQ);
|
||||
|
||||
target->max_scat_entries = MAX_SCATTER_ENTRIES_PER_REQ;
|
||||
target->max_xfer_szper_scatreq =
|
||||
MAX_SCATTER_REQ_TRANSFER_SIZE;
|
||||
} else {
|
||||
ath6kl_sdio_cleanup_scatter(ar);
|
||||
ath6kl_warn("hif scatter resource setup failed, trying virtual scatter method\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (virt_scat || ret) {
|
||||
ret = ath6kl_sdio_alloc_prep_scat_req(ar_sdio,
|
||||
ATH6KL_SCATTER_ENTRIES_PER_REQ,
|
||||
ATH6KL_SCATTER_REQS, virt_scat);
|
||||
|
||||
if (ret) {
|
||||
ath6kl_err("failed to alloc virtual scatter resources !\n");
|
||||
ath6kl_sdio_cleanup_scatter(ar);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_ANY,
|
||||
"Vitual scatter enabled, max_scat_req:%d, entries:%d\n",
|
||||
ATH6KL_SCATTER_REQS, ATH6KL_SCATTER_ENTRIES_PER_REQ);
|
||||
|
||||
target->max_scat_entries = ATH6KL_SCATTER_ENTRIES_PER_REQ;
|
||||
target->max_xfer_szper_scatreq =
|
||||
ATH6KL_MAX_TRANSFER_SIZE_PER_SCATTER;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ath6kl_hif_ops ath6kl_sdio_ops = {
|
||||
.read_write_sync = ath6kl_sdio_read_write_sync,
|
||||
.write_async = ath6kl_sdio_write_async,
|
||||
.irq_enable = ath6kl_sdio_irq_enable,
|
||||
.irq_disable = ath6kl_sdio_irq_disable,
|
||||
.scatter_req_get = ath6kl_sdio_scatter_req_get,
|
||||
.scatter_req_add = ath6kl_sdio_scatter_req_add,
|
||||
.enable_scatter = ath6kl_sdio_enable_scatter,
|
||||
.scat_req_rw = ath6kl_sdio_async_rw_scatter,
|
||||
.cleanup_scatter = ath6kl_sdio_cleanup_scatter,
|
||||
};
|
||||
|
||||
static int ath6kl_sdio_probe(struct sdio_func *func,
|
||||
const struct sdio_device_id *id)
|
||||
{
|
||||
int ret;
|
||||
struct ath6kl_sdio *ar_sdio;
|
||||
struct ath6kl *ar;
|
||||
int count;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_TRC,
|
||||
"%s: func: 0x%X, vendor id: 0x%X, dev id: 0x%X, block size: 0x%X/0x%X\n",
|
||||
__func__, func->num, func->vendor,
|
||||
func->device, func->max_blksize, func->cur_blksize);
|
||||
|
||||
ar_sdio = kzalloc(sizeof(struct ath6kl_sdio), GFP_KERNEL);
|
||||
if (!ar_sdio)
|
||||
return -ENOMEM;
|
||||
|
||||
ar_sdio->dma_buffer = kzalloc(HIF_DMA_BUFFER_SIZE, GFP_KERNEL);
|
||||
if (!ar_sdio->dma_buffer) {
|
||||
ret = -ENOMEM;
|
||||
goto err_hif;
|
||||
}
|
||||
|
||||
ar_sdio->func = func;
|
||||
sdio_set_drvdata(func, ar_sdio);
|
||||
|
||||
ar_sdio->id = id;
|
||||
ar_sdio->is_disabled = true;
|
||||
|
||||
spin_lock_init(&ar_sdio->lock);
|
||||
spin_lock_init(&ar_sdio->scat_lock);
|
||||
spin_lock_init(&ar_sdio->wr_async_lock);
|
||||
|
||||
INIT_LIST_HEAD(&ar_sdio->scat_req);
|
||||
INIT_LIST_HEAD(&ar_sdio->bus_req_freeq);
|
||||
INIT_LIST_HEAD(&ar_sdio->wr_asyncq);
|
||||
|
||||
INIT_WORK(&ar_sdio->wr_async_work, ath6kl_sdio_write_async_work);
|
||||
|
||||
for (count = 0; count < BUS_REQUEST_MAX_NUM; count++)
|
||||
ath6kl_sdio_free_bus_req(ar_sdio, &ar_sdio->bus_req[count]);
|
||||
|
||||
ar = ath6kl_core_alloc(&ar_sdio->func->dev);
|
||||
if (!ar) {
|
||||
ath6kl_err("Failed to alloc ath6kl core\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_dma;
|
||||
}
|
||||
|
||||
ar_sdio->ar = ar;
|
||||
ar->hif_priv = ar_sdio;
|
||||
ar->hif_ops = &ath6kl_sdio_ops;
|
||||
|
||||
ath6kl_sdio_set_mbox_info(ar);
|
||||
|
||||
sdio_claim_host(func);
|
||||
|
||||
if ((ar_sdio->id->device & MANUFACTURER_ID_ATH6KL_BASE_MASK) >=
|
||||
MANUFACTURER_ID_AR6003_BASE) {
|
||||
/* enable 4-bit ASYNC interrupt on AR6003 or later */
|
||||
ret = ath6kl_sdio_func0_cmd52_wr_byte(func->card,
|
||||
CCCR_SDIO_IRQ_MODE_REG,
|
||||
SDIO_IRQ_MODE_ASYNC_4BIT_IRQ);
|
||||
if (ret) {
|
||||
ath6kl_err("Failed to enable 4-bit async irq mode %d\n",
|
||||
ret);
|
||||
sdio_release_host(func);
|
||||
goto err_dma;
|
||||
}
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_TRC, "4-bit async irq mode enabled\n");
|
||||
}
|
||||
|
||||
/* give us some time to enable, in ms */
|
||||
func->enable_timeout = 100;
|
||||
|
||||
sdio_release_host(func);
|
||||
|
||||
ret = ath6kl_sdio_power_on(ar_sdio);
|
||||
if (ret)
|
||||
goto err_dma;
|
||||
|
||||
sdio_claim_host(func);
|
||||
|
||||
ret = sdio_set_block_size(func, HIF_MBOX_BLOCK_SIZE);
|
||||
if (ret) {
|
||||
ath6kl_err("Set sdio block size %d failed: %d)\n",
|
||||
HIF_MBOX_BLOCK_SIZE, ret);
|
||||
sdio_release_host(func);
|
||||
goto err_off;
|
||||
}
|
||||
|
||||
sdio_release_host(func);
|
||||
|
||||
ret = ath6kl_core_init(ar);
|
||||
if (ret) {
|
||||
ath6kl_err("Failed to init ath6kl core\n");
|
||||
goto err_off;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
err_off:
|
||||
ath6kl_sdio_power_off(ar_sdio);
|
||||
err_dma:
|
||||
kfree(ar_sdio->dma_buffer);
|
||||
err_hif:
|
||||
kfree(ar_sdio);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ath6kl_sdio_remove(struct sdio_func *func)
|
||||
{
|
||||
struct ath6kl_sdio *ar_sdio;
|
||||
|
||||
ar_sdio = sdio_get_drvdata(func);
|
||||
|
||||
ath6kl_stop_txrx(ar_sdio->ar);
|
||||
cancel_work_sync(&ar_sdio->wr_async_work);
|
||||
|
||||
ath6kl_unavail_ev(ar_sdio->ar);
|
||||
|
||||
ath6kl_sdio_power_off(ar_sdio);
|
||||
|
||||
kfree(ar_sdio->dma_buffer);
|
||||
kfree(ar_sdio);
|
||||
}
|
||||
|
||||
static const struct sdio_device_id ath6kl_sdio_devices[] = {
|
||||
{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x0))},
|
||||
{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x1))},
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(sdio, ath6kl_sdio_devices);
|
||||
|
||||
static struct sdio_driver ath6kl_sdio_driver = {
|
||||
.name = "ath6kl_sdio",
|
||||
.id_table = ath6kl_sdio_devices,
|
||||
.probe = ath6kl_sdio_probe,
|
||||
.remove = ath6kl_sdio_remove,
|
||||
};
|
||||
|
||||
static int __init ath6kl_sdio_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = sdio_register_driver(&ath6kl_sdio_driver);
|
||||
if (ret)
|
||||
ath6kl_err("sdio driver registration failed: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit ath6kl_sdio_exit(void)
|
||||
{
|
||||
sdio_unregister_driver(&ath6kl_sdio_driver);
|
||||
}
|
||||
|
||||
module_init(ath6kl_sdio_init);
|
||||
module_exit(ath6kl_sdio_exit);
|
||||
|
||||
MODULE_AUTHOR("Atheros Communications, Inc.");
|
||||
MODULE_DESCRIPTION("Driver support for Atheros AR600x SDIO devices");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
|
||||
MODULE_FIRMWARE(AR6003_REV2_OTP_FILE);
|
||||
MODULE_FIRMWARE(AR6003_REV2_FIRMWARE_FILE);
|
||||
MODULE_FIRMWARE(AR6003_REV2_PATCH_FILE);
|
||||
MODULE_FIRMWARE(AR6003_REV2_BOARD_DATA_FILE);
|
||||
MODULE_FIRMWARE(AR6003_REV2_DEFAULT_BOARD_DATA_FILE);
|
||||
MODULE_FIRMWARE(AR6003_REV3_OTP_FILE);
|
||||
MODULE_FIRMWARE(AR6003_REV3_FIRMWARE_FILE);
|
||||
MODULE_FIRMWARE(AR6003_REV3_PATCH_FILE);
|
||||
MODULE_FIRMWARE(AR6003_REV3_BOARD_DATA_FILE);
|
||||
MODULE_FIRMWARE(AR6003_REV3_DEFAULT_BOARD_DATA_FILE);
|
|
@ -0,0 +1,331 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2010 Atheros Communications 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 TARGET_H
|
||||
#define TARGET_H
|
||||
|
||||
#define AR6003_BOARD_DATA_SZ 1024
|
||||
#define AR6003_BOARD_EXT_DATA_SZ 768
|
||||
|
||||
#define RESET_CONTROL_ADDRESS 0x00000000
|
||||
#define RESET_CONTROL_COLD_RST 0x00000100
|
||||
#define RESET_CONTROL_MBOX_RST 0x00000004
|
||||
|
||||
#define CPU_CLOCK_STANDARD_S 0
|
||||
#define CPU_CLOCK_STANDARD 0x00000003
|
||||
#define CPU_CLOCK_ADDRESS 0x00000020
|
||||
|
||||
#define CLOCK_CONTROL_ADDRESS 0x00000028
|
||||
#define CLOCK_CONTROL_LF_CLK32_S 2
|
||||
#define CLOCK_CONTROL_LF_CLK32 0x00000004
|
||||
|
||||
#define SYSTEM_SLEEP_ADDRESS 0x000000c4
|
||||
#define SYSTEM_SLEEP_DISABLE_S 0
|
||||
#define SYSTEM_SLEEP_DISABLE 0x00000001
|
||||
|
||||
#define LPO_CAL_ADDRESS 0x000000e0
|
||||
#define LPO_CAL_ENABLE_S 20
|
||||
#define LPO_CAL_ENABLE 0x00100000
|
||||
|
||||
#define GPIO_PIN10_ADDRESS 0x00000050
|
||||
#define GPIO_PIN11_ADDRESS 0x00000054
|
||||
#define GPIO_PIN12_ADDRESS 0x00000058
|
||||
#define GPIO_PIN13_ADDRESS 0x0000005c
|
||||
|
||||
#define HOST_INT_STATUS_ADDRESS 0x00000400
|
||||
#define HOST_INT_STATUS_ERROR_S 7
|
||||
#define HOST_INT_STATUS_ERROR 0x00000080
|
||||
|
||||
#define HOST_INT_STATUS_CPU_S 6
|
||||
#define HOST_INT_STATUS_CPU 0x00000040
|
||||
|
||||
#define HOST_INT_STATUS_COUNTER_S 4
|
||||
#define HOST_INT_STATUS_COUNTER 0x00000010
|
||||
|
||||
#define CPU_INT_STATUS_ADDRESS 0x00000401
|
||||
|
||||
#define ERROR_INT_STATUS_ADDRESS 0x00000402
|
||||
#define ERROR_INT_STATUS_WAKEUP_S 2
|
||||
#define ERROR_INT_STATUS_WAKEUP 0x00000004
|
||||
|
||||
#define ERROR_INT_STATUS_RX_UNDERFLOW_S 1
|
||||
#define ERROR_INT_STATUS_RX_UNDERFLOW 0x00000002
|
||||
|
||||
#define ERROR_INT_STATUS_TX_OVERFLOW_S 0
|
||||
#define ERROR_INT_STATUS_TX_OVERFLOW 0x00000001
|
||||
|
||||
#define COUNTER_INT_STATUS_ADDRESS 0x00000403
|
||||
#define COUNTER_INT_STATUS_COUNTER_S 0
|
||||
#define COUNTER_INT_STATUS_COUNTER 0x000000ff
|
||||
|
||||
#define RX_LOOKAHEAD_VALID_ADDRESS 0x00000405
|
||||
|
||||
#define INT_STATUS_ENABLE_ADDRESS 0x00000418
|
||||
#define INT_STATUS_ENABLE_ERROR_S 7
|
||||
#define INT_STATUS_ENABLE_ERROR 0x00000080
|
||||
|
||||
#define INT_STATUS_ENABLE_CPU_S 6
|
||||
#define INT_STATUS_ENABLE_CPU 0x00000040
|
||||
|
||||
#define INT_STATUS_ENABLE_INT_S 5
|
||||
#define INT_STATUS_ENABLE_INT 0x00000020
|
||||
#define INT_STATUS_ENABLE_COUNTER_S 4
|
||||
#define INT_STATUS_ENABLE_COUNTER 0x00000010
|
||||
|
||||
#define INT_STATUS_ENABLE_MBOX_DATA_S 0
|
||||
#define INT_STATUS_ENABLE_MBOX_DATA 0x0000000f
|
||||
|
||||
#define CPU_INT_STATUS_ENABLE_ADDRESS 0x00000419
|
||||
#define CPU_INT_STATUS_ENABLE_BIT_S 0
|
||||
#define CPU_INT_STATUS_ENABLE_BIT 0x000000ff
|
||||
|
||||
#define ERROR_STATUS_ENABLE_ADDRESS 0x0000041a
|
||||
#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_S 1
|
||||
#define ERROR_STATUS_ENABLE_RX_UNDERFLOW 0x00000002
|
||||
|
||||
#define ERROR_STATUS_ENABLE_TX_OVERFLOW_S 0
|
||||
#define ERROR_STATUS_ENABLE_TX_OVERFLOW 0x00000001
|
||||
|
||||
#define COUNTER_INT_STATUS_ENABLE_ADDRESS 0x0000041b
|
||||
#define COUNTER_INT_STATUS_ENABLE_BIT_S 0
|
||||
#define COUNTER_INT_STATUS_ENABLE_BIT 0x000000ff
|
||||
|
||||
#define COUNT_ADDRESS 0x00000420
|
||||
|
||||
#define COUNT_DEC_ADDRESS 0x00000440
|
||||
|
||||
#define WINDOW_DATA_ADDRESS 0x00000474
|
||||
#define WINDOW_WRITE_ADDR_ADDRESS 0x00000478
|
||||
#define WINDOW_READ_ADDR_ADDRESS 0x0000047c
|
||||
#define CPU_DBG_SEL_ADDRESS 0x00000483
|
||||
#define CPU_DBG_ADDRESS 0x00000484
|
||||
|
||||
#define LOCAL_SCRATCH_ADDRESS 0x000000c0
|
||||
#define ATH6KL_OPTION_SLEEP_DISABLE 0x08
|
||||
|
||||
#define RTC_BASE_ADDRESS 0x00004000
|
||||
#define GPIO_BASE_ADDRESS 0x00014000
|
||||
#define MBOX_BASE_ADDRESS 0x00018000
|
||||
#define ANALOG_INTF_BASE_ADDRESS 0x0001c000
|
||||
|
||||
/* real name of the register is unknown */
|
||||
#define ATH6KL_ANALOG_PLL_REGISTER (ANALOG_INTF_BASE_ADDRESS + 0x284)
|
||||
|
||||
#define SM(f, v) (((v) << f##_S) & f)
|
||||
#define MS(f, v) (((v) & f) >> f##_S)
|
||||
|
||||
/*
|
||||
* xxx_HOST_INTEREST_ADDRESS is the address in Target RAM of the
|
||||
* host_interest structure.
|
||||
*
|
||||
* Host Interest is shared between Host and Target in order to coordinate
|
||||
* between the two, and is intended to remain constant (with additions only
|
||||
* at the end).
|
||||
*/
|
||||
#define ATH6KL_HI_START_ADDR 0x00540600
|
||||
|
||||
/*
|
||||
* These are items that the Host may need to access
|
||||
* via BMI or via the Diagnostic Window. The position
|
||||
* of items in this structure must remain constant.
|
||||
* across firmware revisions!
|
||||
*
|
||||
* Types for each item must be fixed size across target and host platforms.
|
||||
* The structure is used only to calculate offset for each register with
|
||||
* HI_ITEM() macro, no values are stored to it.
|
||||
*
|
||||
* More items may be added at the end.
|
||||
*/
|
||||
struct host_interest {
|
||||
/*
|
||||
* Pointer to application-defined area, if any.
|
||||
* Set by Target application during startup.
|
||||
*/
|
||||
u32 hi_app_host_interest; /* 0x00 */
|
||||
|
||||
/* Pointer to register dump area, valid after Target crash. */
|
||||
u32 hi_failure_state; /* 0x04 */
|
||||
|
||||
/* Pointer to debug logging header */
|
||||
u32 hi_dbglog_hdr; /* 0x08 */
|
||||
|
||||
u32 hi_unused1; /* 0x0c */
|
||||
|
||||
/*
|
||||
* General-purpose flag bits, similar to ATH6KL_OPTION_* flags.
|
||||
* Can be used by application rather than by OS.
|
||||
*/
|
||||
u32 hi_option_flag; /* 0x10 */
|
||||
|
||||
/*
|
||||
* Boolean that determines whether or not to
|
||||
* display messages on the serial port.
|
||||
*/
|
||||
u32 hi_serial_enable; /* 0x14 */
|
||||
|
||||
/* Start address of DataSet index, if any */
|
||||
u32 hi_dset_list_head; /* 0x18 */
|
||||
|
||||
/* Override Target application start address */
|
||||
u32 hi_app_start; /* 0x1c */
|
||||
|
||||
/* Clock and voltage tuning */
|
||||
u32 hi_skip_clock_init; /* 0x20 */
|
||||
u32 hi_core_clock_setting; /* 0x24 */
|
||||
u32 hi_cpu_clock_setting; /* 0x28 */
|
||||
u32 hi_system_sleep_setting; /* 0x2c */
|
||||
u32 hi_xtal_control_setting; /* 0x30 */
|
||||
u32 hi_pll_ctrl_setting_24ghz; /* 0x34 */
|
||||
u32 hi_pll_ctrl_setting_5ghz; /* 0x38 */
|
||||
u32 hi_ref_voltage_trim_setting; /* 0x3c */
|
||||
u32 hi_clock_info; /* 0x40 */
|
||||
|
||||
/*
|
||||
* Flash configuration overrides, used only
|
||||
* when firmware is not executing from flash.
|
||||
* (When using flash, modify the global variables
|
||||
* with equivalent names.)
|
||||
*/
|
||||
u32 hi_bank0_addr_value; /* 0x44 */
|
||||
u32 hi_bank0_read_value; /* 0x48 */
|
||||
u32 hi_bank0_write_value; /* 0x4c */
|
||||
u32 hi_bank0_config_value; /* 0x50 */
|
||||
|
||||
/* Pointer to Board Data */
|
||||
u32 hi_board_data; /* 0x54 */
|
||||
u32 hi_board_data_initialized; /* 0x58 */
|
||||
|
||||
u32 hi_dset_ram_index_tbl; /* 0x5c */
|
||||
|
||||
u32 hi_desired_baud_rate; /* 0x60 */
|
||||
u32 hi_dbglog_config; /* 0x64 */
|
||||
u32 hi_end_ram_reserve_sz; /* 0x68 */
|
||||
u32 hi_mbox_io_block_sz; /* 0x6c */
|
||||
|
||||
u32 hi_num_bpatch_streams; /* 0x70 -- unused */
|
||||
u32 hi_mbox_isr_yield_limit; /* 0x74 */
|
||||
|
||||
u32 hi_refclk_hz; /* 0x78 */
|
||||
u32 hi_ext_clk_detected; /* 0x7c */
|
||||
u32 hi_dbg_uart_txpin; /* 0x80 */
|
||||
u32 hi_dbg_uart_rxpin; /* 0x84 */
|
||||
u32 hi_hci_uart_baud; /* 0x88 */
|
||||
u32 hi_hci_uart_pin_assignments; /* 0x8C */
|
||||
/*
|
||||
* NOTE: byte [0] = tx pin, [1] = rx pin, [2] = rts pin, [3] = cts
|
||||
* pin
|
||||
*/
|
||||
u32 hi_hci_uart_baud_scale_val; /* 0x90 */
|
||||
u32 hi_hci_uart_baud_step_val; /* 0x94 */
|
||||
|
||||
u32 hi_allocram_start; /* 0x98 */
|
||||
u32 hi_allocram_sz; /* 0x9c */
|
||||
u32 hi_hci_bridge_flags; /* 0xa0 */
|
||||
u32 hi_hci_uart_support_pins; /* 0xa4 */
|
||||
/*
|
||||
* NOTE: byte [0] = RESET pin (bit 7 is polarity),
|
||||
* bytes[1]..bytes[3] are for future use
|
||||
*/
|
||||
u32 hi_hci_uart_pwr_mgmt_params; /* 0xa8 */
|
||||
/*
|
||||
* 0xa8 - [1]: 0 = UART FC active low, 1 = UART FC active high
|
||||
* [31:16]: wakeup timeout in ms
|
||||
*/
|
||||
|
||||
/* Pointer to extended board data */
|
||||
u32 hi_board_ext_data; /* 0xac */
|
||||
u32 hi_board_ext_data_config; /* 0xb0 */
|
||||
|
||||
/*
|
||||
* Bit [0] : valid
|
||||
* Bit[31:16: size
|
||||
*/
|
||||
/*
|
||||
* hi_reset_flag is used to do some stuff when target reset.
|
||||
* such as restore app_start after warm reset or
|
||||
* preserve host Interest area, or preserve ROM data, literals etc.
|
||||
*/
|
||||
u32 hi_reset_flag; /* 0xb4 */
|
||||
/* indicate hi_reset_flag is valid */
|
||||
u32 hi_reset_flag_valid; /* 0xb8 */
|
||||
u32 hi_hci_uart_pwr_mgmt_params_ext; /* 0xbc */
|
||||
/*
|
||||
* 0xbc - [31:0]: idle timeout in ms
|
||||
*/
|
||||
/* ACS flags */
|
||||
u32 hi_acs_flags; /* 0xc0 */
|
||||
u32 hi_console_flags; /* 0xc4 */
|
||||
u32 hi_nvram_state; /* 0xc8 */
|
||||
u32 hi_option_flag2; /* 0xcc */
|
||||
|
||||
/* If non-zero, override values sent to Host in WMI_READY event. */
|
||||
u32 hi_sw_version_override; /* 0xd0 */
|
||||
u32 hi_abi_version_override; /* 0xd4 */
|
||||
|
||||
/*
|
||||
* Percentage of high priority RX traffic to total expected RX traffic -
|
||||
* applicable only to ar6004
|
||||
*/
|
||||
u32 hi_hp_rx_traffic_ratio; /* 0xd8 */
|
||||
|
||||
/* test applications flags */
|
||||
u32 hi_test_apps_related ; /* 0xdc */
|
||||
/* location of test script */
|
||||
u32 hi_ota_testscript; /* 0xe0 */
|
||||
/* location of CAL data */
|
||||
u32 hi_cal_data; /* 0xe4 */
|
||||
/* Number of packet log buffers */
|
||||
u32 hi_pktlog_num_buffers; /* 0xe8 */
|
||||
|
||||
} __packed;
|
||||
|
||||
#define HI_ITEM(item) offsetof(struct host_interest, item)
|
||||
|
||||
#define HI_OPTION_MAC_ADDR_METHOD_SHIFT 3
|
||||
|
||||
#define HI_OPTION_FW_MODE_IBSS 0x0
|
||||
#define HI_OPTION_FW_MODE_BSS_STA 0x1
|
||||
#define HI_OPTION_FW_MODE_AP 0x2
|
||||
|
||||
#define HI_OPTION_NUM_DEV_SHIFT 0x9
|
||||
|
||||
#define HI_OPTION_FW_BRIDGE_SHIFT 0x04
|
||||
|
||||
/* Fw Mode/SubMode Mask
|
||||
|------------------------------------------------------------------------------|
|
||||
| SUB | SUB | SUB | SUB | | | |
|
||||
| MODE[3] | MODE[2] | MODE[1] | MODE[0] | MODE[3] | MODE[2] | MODE[1] | MODE[0|
|
||||
| (2) | (2) | (2) | (2) | (2) | (2) | (2) | (2)
|
||||
|------------------------------------------------------------------------------|
|
||||
*/
|
||||
#define HI_OPTION_FW_MODE_SHIFT 0xC
|
||||
|
||||
/* Convert a Target virtual address into a Target physical address */
|
||||
#define TARG_VTOP(vaddr) (vaddr & 0x001fffff)
|
||||
|
||||
#define AR6003_REV2_APP_START_OVERRIDE 0x944C00
|
||||
#define AR6003_REV2_APP_LOAD_ADDRESS 0x543180
|
||||
#define AR6003_REV2_BOARD_EXT_DATA_ADDRESS 0x57E500
|
||||
#define AR6003_REV2_DATASET_PATCH_ADDRESS 0x57e884
|
||||
#define AR6003_REV2_RAM_RESERVE_SIZE 6912
|
||||
|
||||
#define AR6003_REV3_APP_START_OVERRIDE 0x945d00
|
||||
#define AR6003_REV3_APP_LOAD_ADDRESS 0x545000
|
||||
#define AR6003_REV3_BOARD_EXT_DATA_ADDRESS 0x542330
|
||||
#define AR6003_REV3_DATASET_PATCH_ADDRESS 0x57FF74
|
||||
#define AR6003_REV3_RAM_RESERVE_SIZE 512
|
||||
|
||||
#endif
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -133,7 +133,7 @@ static int ath_ahb_probe(struct platform_device *pdev)
|
|||
goto err_free_hw;
|
||||
}
|
||||
|
||||
ret = ath9k_init_device(id->driver_data, sc, 0x0, &ath_ahb_bus_ops);
|
||||
ret = ath9k_init_device(id->driver_data, sc, &ath_ahb_bus_ops);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to initialize device\n");
|
||||
goto err_irq;
|
||||
|
|
|
@ -835,108 +835,108 @@ static const u32 ar9300_2p2_baseband_core[][2] = {
|
|||
|
||||
static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = {
|
||||
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
|
||||
{0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
|
||||
{0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
|
||||
{0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
|
||||
{0x0000a2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
|
||||
{0x0000a2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
|
||||
{0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
|
||||
{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
|
||||
{0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
|
||||
{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
|
||||
{0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
|
||||
{0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004},
|
||||
{0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200},
|
||||
{0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202},
|
||||
{0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400},
|
||||
{0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402},
|
||||
{0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404},
|
||||
{0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603},
|
||||
{0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02},
|
||||
{0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04},
|
||||
{0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20},
|
||||
{0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20},
|
||||
{0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22},
|
||||
{0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24},
|
||||
{0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640},
|
||||
{0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660},
|
||||
{0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861},
|
||||
{0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81},
|
||||
{0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83},
|
||||
{0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84},
|
||||
{0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3},
|
||||
{0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5},
|
||||
{0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9},
|
||||
{0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb},
|
||||
{0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
|
||||
{0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
|
||||
{0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
|
||||
{0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
|
||||
{0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
|
||||
{0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
|
||||
{0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
|
||||
{0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000},
|
||||
{0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002},
|
||||
{0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004},
|
||||
{0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200},
|
||||
{0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202},
|
||||
{0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400},
|
||||
{0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402},
|
||||
{0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404},
|
||||
{0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603},
|
||||
{0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02},
|
||||
{0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04},
|
||||
{0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20},
|
||||
{0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20},
|
||||
{0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22},
|
||||
{0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24},
|
||||
{0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640},
|
||||
{0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660},
|
||||
{0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861},
|
||||
{0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81},
|
||||
{0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83},
|
||||
{0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84},
|
||||
{0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3},
|
||||
{0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5},
|
||||
{0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9},
|
||||
{0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb},
|
||||
{0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
|
||||
{0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
|
||||
{0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
|
||||
{0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
|
||||
{0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
|
||||
{0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
|
||||
{0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
|
||||
{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, 0x12000400, 0x12000400},
|
||||
{0x0000a518, 0x21002220, 0x21002220, 0x16000402, 0x16000402},
|
||||
{0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404},
|
||||
{0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603},
|
||||
{0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02},
|
||||
{0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04},
|
||||
{0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20},
|
||||
{0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20},
|
||||
{0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22},
|
||||
{0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24},
|
||||
{0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640},
|
||||
{0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660},
|
||||
{0x0000a544, 0x52022470, 0x52022470, 0x3f001861, 0x3f001861},
|
||||
{0x0000a548, 0x55022490, 0x55022490, 0x43001a81, 0x43001a81},
|
||||
{0x0000a54c, 0x59022492, 0x59022492, 0x47001a83, 0x47001a83},
|
||||
{0x0000a550, 0x5d022692, 0x5d022692, 0x4a001c84, 0x4a001c84},
|
||||
{0x0000a554, 0x61022892, 0x61022892, 0x4e001ce3, 0x4e001ce3},
|
||||
{0x0000a558, 0x65024890, 0x65024890, 0x52001ce5, 0x52001ce5},
|
||||
{0x0000a55c, 0x69024892, 0x69024892, 0x56001ce9, 0x56001ce9},
|
||||
{0x0000a560, 0x6e024c92, 0x6e024c92, 0x5a001ceb, 0x5a001ceb},
|
||||
{0x0000a564, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
|
||||
{0x0000a568, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
|
||||
{0x0000a56c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
|
||||
{0x0000a570, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
|
||||
{0x0000a574, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
|
||||
{0x0000a578, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
|
||||
{0x0000a57c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
|
||||
{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, 0x12800400, 0x12800400},
|
||||
{0x0000a598, 0x21802220, 0x21802220, 0x16800402, 0x16800402},
|
||||
{0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404},
|
||||
{0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603},
|
||||
{0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02},
|
||||
{0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04},
|
||||
{0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20},
|
||||
{0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20},
|
||||
{0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22},
|
||||
{0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24},
|
||||
{0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640},
|
||||
{0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660},
|
||||
{0x0000a5c4, 0x52822470, 0x52822470, 0x3f801861, 0x3f801861},
|
||||
{0x0000a5c8, 0x55822490, 0x55822490, 0x43801a81, 0x43801a81},
|
||||
{0x0000a5cc, 0x59822492, 0x59822492, 0x47801a83, 0x47801a83},
|
||||
{0x0000a5d0, 0x5d822692, 0x5d822692, 0x4a801c84, 0x4a801c84},
|
||||
{0x0000a5d4, 0x61822892, 0x61822892, 0x4e801ce3, 0x4e801ce3},
|
||||
{0x0000a5d8, 0x65824890, 0x65824890, 0x52801ce5, 0x52801ce5},
|
||||
{0x0000a5dc, 0x69824892, 0x69824892, 0x56801ce9, 0x56801ce9},
|
||||
{0x0000a5e0, 0x6e824c92, 0x6e824c92, 0x5a801ceb, 0x5a801ceb},
|
||||
{0x0000a5e4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
|
||||
{0x0000a5e8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
|
||||
{0x0000a5ec, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
|
||||
{0x0000a5f0, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
|
||||
{0x0000a5f4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
|
||||
{0x0000a5f8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
|
||||
{0x0000a5fc, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
|
||||
{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||
{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||
{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||
{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||
{0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000},
|
||||
{0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000},
|
||||
{0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501},
|
||||
{0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501},
|
||||
{0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03},
|
||||
{0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04},
|
||||
{0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04},
|
||||
{0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
|
||||
{0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
|
||||
{0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
|
||||
{0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
|
||||
{0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
|
||||
{0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
|
||||
{0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
|
||||
{0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
|
||||
{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, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
|
||||
{0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
|
||||
{0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
|
||||
{0x0000c2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
|
||||
{0x0000c2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
|
||||
{0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
|
||||
{0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
|
||||
{0x00016044, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
|
||||
{0x00016048, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
|
||||
{0x00016068, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
|
||||
{0x00016444, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
|
||||
{0x00016448, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
|
||||
{0x00016468, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
|
||||
{0x00016844, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
|
||||
{0x00016848, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
|
||||
{0x00016868, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
|
||||
{0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
|
||||
{0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
|
||||
{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
|
||||
{0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
|
||||
{0x00016448, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
|
||||
{0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
|
||||
{0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
|
||||
{0x00016848, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
|
||||
{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
|
||||
};
|
||||
|
||||
static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = {
|
||||
|
|
|
@ -3418,6 +3418,133 @@ static bool ath9k_hw_ar9300_fill_eeprom(struct ath_hw *ah)
|
|||
return true;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_ATH9K_DEBUGFS) || defined(CONFIG_ATH9K_HTC_DEBUGFS)
|
||||
static u32 ar9003_dump_modal_eeprom(char *buf, u32 len, u32 size,
|
||||
struct ar9300_modal_eep_header *modal_hdr)
|
||||
{
|
||||
PR_EEP("Chain0 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[0]));
|
||||
PR_EEP("Chain1 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[1]));
|
||||
PR_EEP("Chain2 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[2]));
|
||||
PR_EEP("Ant. Common Control", le32_to_cpu(modal_hdr->antCtrlCommon));
|
||||
PR_EEP("Ant. Common Control2", le32_to_cpu(modal_hdr->antCtrlCommon2));
|
||||
PR_EEP("Ant. Gain", modal_hdr->antennaGain);
|
||||
PR_EEP("Switch Settle", modal_hdr->switchSettling);
|
||||
PR_EEP("Chain0 xatten1DB", modal_hdr->xatten1DB[0]);
|
||||
PR_EEP("Chain1 xatten1DB", modal_hdr->xatten1DB[1]);
|
||||
PR_EEP("Chain2 xatten1DB", modal_hdr->xatten1DB[2]);
|
||||
PR_EEP("Chain0 xatten1Margin", modal_hdr->xatten1Margin[0]);
|
||||
PR_EEP("Chain1 xatten1Margin", modal_hdr->xatten1Margin[1]);
|
||||
PR_EEP("Chain2 xatten1Margin", modal_hdr->xatten1Margin[2]);
|
||||
PR_EEP("Temp Slope", modal_hdr->tempSlope);
|
||||
PR_EEP("Volt Slope", modal_hdr->voltSlope);
|
||||
PR_EEP("spur Channels0", modal_hdr->spurChans[0]);
|
||||
PR_EEP("spur Channels1", modal_hdr->spurChans[1]);
|
||||
PR_EEP("spur Channels2", modal_hdr->spurChans[2]);
|
||||
PR_EEP("spur Channels3", modal_hdr->spurChans[3]);
|
||||
PR_EEP("spur Channels4", modal_hdr->spurChans[4]);
|
||||
PR_EEP("Chain0 NF Threshold", modal_hdr->noiseFloorThreshCh[0]);
|
||||
PR_EEP("Chain1 NF Threshold", modal_hdr->noiseFloorThreshCh[1]);
|
||||
PR_EEP("Chain2 NF Threshold", modal_hdr->noiseFloorThreshCh[2]);
|
||||
PR_EEP("xPA Bias Level", modal_hdr->xpaBiasLvl);
|
||||
PR_EEP("txFrameToDataStart", modal_hdr->txFrameToDataStart);
|
||||
PR_EEP("txFrameToPaOn", modal_hdr->txFrameToPaOn);
|
||||
PR_EEP("txFrameToXpaOn", modal_hdr->txFrameToXpaOn);
|
||||
PR_EEP("txClip", modal_hdr->txClip);
|
||||
PR_EEP("ADC Desired size", modal_hdr->adcDesiredSize);
|
||||
PR_EEP("Chain0 ob", modal_hdr->ob[0]);
|
||||
PR_EEP("Chain1 ob", modal_hdr->ob[1]);
|
||||
PR_EEP("Chain2 ob", modal_hdr->ob[2]);
|
||||
|
||||
PR_EEP("Chain0 db_stage2", modal_hdr->db_stage2[0]);
|
||||
PR_EEP("Chain1 db_stage2", modal_hdr->db_stage2[1]);
|
||||
PR_EEP("Chain2 db_stage2", modal_hdr->db_stage2[2]);
|
||||
PR_EEP("Chain0 db_stage3", modal_hdr->db_stage3[0]);
|
||||
PR_EEP("Chain1 db_stage3", modal_hdr->db_stage3[1]);
|
||||
PR_EEP("Chain2 db_stage3", modal_hdr->db_stage3[2]);
|
||||
PR_EEP("Chain0 db_stage4", modal_hdr->db_stage4[0]);
|
||||
PR_EEP("Chain1 db_stage4", modal_hdr->db_stage4[1]);
|
||||
PR_EEP("Chain2 db_stage4", modal_hdr->db_stage4[2]);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
|
||||
u8 *buf, u32 len, u32 size)
|
||||
{
|
||||
struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
|
||||
struct ar9300_base_eep_hdr *pBase;
|
||||
|
||||
if (!dump_base_hdr) {
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%20s :\n", "2GHz modal Header");
|
||||
len += ar9003_dump_modal_eeprom(buf, len, size,
|
||||
&eep->modalHeader2G);
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%20s :\n", "5GHz modal Header");
|
||||
len += ar9003_dump_modal_eeprom(buf, len, size,
|
||||
&eep->modalHeader5G);
|
||||
goto out;
|
||||
}
|
||||
|
||||
pBase = &eep->baseEepHeader;
|
||||
|
||||
PR_EEP("EEPROM Version", ah->eeprom.ar9300_eep.eepromVersion);
|
||||
PR_EEP("RegDomain1", le16_to_cpu(pBase->regDmn[0]));
|
||||
PR_EEP("RegDomain2", le16_to_cpu(pBase->regDmn[1]));
|
||||
PR_EEP("TX Mask", (pBase->txrxMask >> 4));
|
||||
PR_EEP("RX Mask", (pBase->txrxMask & 0x0f));
|
||||
PR_EEP("Allow 5GHz", !!(pBase->opCapFlags.opFlags &
|
||||
AR5416_OPFLAGS_11A));
|
||||
PR_EEP("Allow 2GHz", !!(pBase->opCapFlags.opFlags &
|
||||
AR5416_OPFLAGS_11G));
|
||||
PR_EEP("Disable 2GHz HT20", !!(pBase->opCapFlags.opFlags &
|
||||
AR5416_OPFLAGS_N_2G_HT20));
|
||||
PR_EEP("Disable 2GHz HT40", !!(pBase->opCapFlags.opFlags &
|
||||
AR5416_OPFLAGS_N_2G_HT40));
|
||||
PR_EEP("Disable 5Ghz HT20", !!(pBase->opCapFlags.opFlags &
|
||||
AR5416_OPFLAGS_N_5G_HT20));
|
||||
PR_EEP("Disable 5Ghz HT40", !!(pBase->opCapFlags.opFlags &
|
||||
AR5416_OPFLAGS_N_5G_HT40));
|
||||
PR_EEP("Big Endian", !!(pBase->opCapFlags.eepMisc & 0x01));
|
||||
PR_EEP("RF Silent", pBase->rfSilent);
|
||||
PR_EEP("BT option", pBase->blueToothOptions);
|
||||
PR_EEP("Device Cap", pBase->deviceCap);
|
||||
PR_EEP("Device Type", pBase->deviceType);
|
||||
PR_EEP("Power Table Offset", pBase->pwrTableOffset);
|
||||
PR_EEP("Tuning Caps1", pBase->params_for_tuning_caps[0]);
|
||||
PR_EEP("Tuning Caps2", pBase->params_for_tuning_caps[1]);
|
||||
PR_EEP("Enable Tx Temp Comp", !!(pBase->featureEnable & BIT(0)));
|
||||
PR_EEP("Enable Tx Volt Comp", !!(pBase->featureEnable & BIT(1)));
|
||||
PR_EEP("Enable fast clock", !!(pBase->featureEnable & BIT(2)));
|
||||
PR_EEP("Enable doubling", !!(pBase->featureEnable & BIT(3)));
|
||||
PR_EEP("Internal regulator", !!(pBase->featureEnable & BIT(4)));
|
||||
PR_EEP("Enable Paprd", !!(pBase->featureEnable & BIT(5)));
|
||||
PR_EEP("Driver Strength", !!(pBase->miscConfiguration & BIT(0)));
|
||||
PR_EEP("Chain mask Reduce", (pBase->miscConfiguration >> 0x3) & 0x1);
|
||||
PR_EEP("Write enable Gpio", pBase->eepromWriteEnableGpio);
|
||||
PR_EEP("WLAN Disable Gpio", pBase->wlanDisableGpio);
|
||||
PR_EEP("WLAN LED Gpio", pBase->wlanLedGpio);
|
||||
PR_EEP("Rx Band Select Gpio", pBase->rxBandSelectGpio);
|
||||
PR_EEP("Tx Gain", pBase->txrxgain >> 4);
|
||||
PR_EEP("Rx Gain", pBase->txrxgain & 0xf);
|
||||
PR_EEP("SW Reg", le32_to_cpu(pBase->swreg));
|
||||
|
||||
len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress",
|
||||
ah->eeprom.ar9300_eep.macAddr);
|
||||
out:
|
||||
if (len > size)
|
||||
len = size;
|
||||
|
||||
return len;
|
||||
}
|
||||
#else
|
||||
static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
|
||||
u8 *buf, u32 len, u32 size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* XXX: review hardware docs */
|
||||
static int ath9k_hw_ar9300_get_eeprom_ver(struct ath_hw *ah)
|
||||
{
|
||||
|
@ -4061,7 +4188,7 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray)
|
|||
/* Write the power for duplicated frames - HT40 */
|
||||
|
||||
/* dup40_cck (LSB), dup40_ofdm, ext20_cck, ext20_ofdm (MSB) */
|
||||
REG_WRITE(ah, 0xa3e0,
|
||||
REG_WRITE(ah, AR_PHY_POWER_TX_RATE(8),
|
||||
POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 24) |
|
||||
POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 16) |
|
||||
POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 8) |
|
||||
|
@ -4922,25 +5049,7 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
|
|||
"TPC[%02d] 0x%08x\n", i, targetPowerValT2[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the TX power we send back to driver core,
|
||||
* and it can use to pass to userspace to display our
|
||||
* currently configured TX power setting.
|
||||
*
|
||||
* Since power is rate dependent, use one of the indices
|
||||
* from the AR9300_Rates enum to select an entry from
|
||||
* targetPowerValT2[] to report. Currently returns the
|
||||
* power for HT40 MCS 0, HT20 MCS 0, or OFDM 6 Mbps
|
||||
* as CCK power is less interesting (?).
|
||||
*/
|
||||
i = ALL_TARGET_LEGACY_6_24; /* legacy */
|
||||
if (IS_CHAN_HT40(chan))
|
||||
i = ALL_TARGET_HT40_0_8_16; /* ht40 */
|
||||
else if (IS_CHAN_HT20(chan))
|
||||
i = ALL_TARGET_HT20_0_8_16; /* ht20 */
|
||||
|
||||
ah->txpower_limit = targetPowerValT2[i];
|
||||
regulatory->max_power_level = targetPowerValT2[i];
|
||||
ah->txpower_limit = regulatory->max_power_level;
|
||||
|
||||
/* Write target power array to registers */
|
||||
ar9003_hw_tx_power_regwrite(ah, targetPowerValT2);
|
||||
|
@ -5015,6 +5124,7 @@ const struct eeprom_ops eep_ar9300_ops = {
|
|||
.check_eeprom = ath9k_hw_ar9300_check_eeprom,
|
||||
.get_eeprom = ath9k_hw_ar9300_get_eeprom,
|
||||
.fill_eeprom = ath9k_hw_ar9300_fill_eeprom,
|
||||
.dump_eeprom = ath9k_hw_ar9003_dump_eeprom,
|
||||
.get_eeprom_ver = ath9k_hw_ar9300_get_eeprom_ver,
|
||||
.get_eeprom_rev = ath9k_hw_ar9300_get_eeprom_rev,
|
||||
.set_board_values = ath9k_hw_ar9300_set_board_values,
|
||||
|
|
|
@ -531,6 +531,7 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs,
|
|||
|
||||
/* TODO: byte swap on big endian for ar9300_10 */
|
||||
|
||||
if (!rxs) {
|
||||
if ((rxsp->status11 & AR_RxDone) == 0)
|
||||
return -EINPROGRESS;
|
||||
|
||||
|
@ -540,8 +541,8 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs,
|
|||
if ((rxsp->ds_info & (AR_TxRxDesc | AR_CtrlStat)) != 0)
|
||||
return -EINPROGRESS;
|
||||
|
||||
if (!rxs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
rxs->rs_status = 0;
|
||||
rxs->rs_flags = 0;
|
||||
|
|
|
@ -370,7 +370,7 @@ static void ar9003_hw_spur_ofdm_work(struct ath_hw *ah,
|
|||
else
|
||||
spur_subchannel_sd = 0;
|
||||
|
||||
spur_freq_sd = ((freq_offset + 10) << 9) / 11;
|
||||
spur_freq_sd = (freq_offset << 9) / 11;
|
||||
|
||||
} else {
|
||||
if (REG_READ_FIELD(ah, AR_PHY_GEN_CTRL,
|
||||
|
@ -379,7 +379,7 @@ static void ar9003_hw_spur_ofdm_work(struct ath_hw *ah,
|
|||
else
|
||||
spur_subchannel_sd = 1;
|
||||
|
||||
spur_freq_sd = ((freq_offset - 10) << 9) / 11;
|
||||
spur_freq_sd = (freq_offset << 9) / 11;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -217,7 +217,6 @@ struct ath_buf_state {
|
|||
u8 bf_type;
|
||||
u8 bfs_paprd;
|
||||
unsigned long bfs_paprd_timestamp;
|
||||
enum ath9k_internal_frame_type bfs_ftype;
|
||||
};
|
||||
|
||||
struct ath_buf {
|
||||
|
@ -273,8 +272,6 @@ struct ath_node {
|
|||
struct ath_tx_control {
|
||||
struct ath_txq *txq;
|
||||
struct ath_node *an;
|
||||
int if_id;
|
||||
enum ath9k_internal_frame_type frame_type;
|
||||
u8 paprd;
|
||||
};
|
||||
|
||||
|
@ -570,7 +567,6 @@ struct ath_ant_comb {
|
|||
#define PS_WAIT_FOR_PSPOLL_DATA BIT(2)
|
||||
#define PS_WAIT_FOR_TX_ACK BIT(3)
|
||||
#define PS_BEACON_SYNC BIT(4)
|
||||
#define PS_TSFOOR_SYNC BIT(5)
|
||||
|
||||
struct ath_rate_table;
|
||||
|
||||
|
@ -669,7 +665,7 @@ extern bool is_ath9k_unloaded;
|
|||
|
||||
irqreturn_t ath_isr(int irq, void *dev);
|
||||
void ath9k_init_crypto(struct ath_softc *sc);
|
||||
int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
|
||||
int ath9k_init_device(u16 devid, struct ath_softc *sc,
|
||||
const struct ath_bus_ops *bus_ops);
|
||||
void ath9k_deinit_device(struct ath_softc *sc);
|
||||
void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw);
|
||||
|
|
|
@ -522,6 +522,7 @@ static void ath_beacon_config_ap(struct ath_softc *sc,
|
|||
ath9k_beacon_init(sc, nexttbtt, intval);
|
||||
sc->beacon.bmisscnt = 0;
|
||||
ath9k_hw_set_interrupts(ah, ah->imask);
|
||||
ath9k_hw_enable_interrupts(ah);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -648,12 +649,8 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
|
|||
ath9k_hw_set_sta_beacon_timers(ah, &bs);
|
||||
ah->imask |= ATH9K_INT_BMISS;
|
||||
|
||||
/*
|
||||
* If the beacon config is called beacause of TSFOOR,
|
||||
* Interrupts will be enabled back at the end of ath9k_tasklet
|
||||
*/
|
||||
if (!(sc->ps_flags & PS_TSFOOR_SYNC))
|
||||
ath9k_hw_set_interrupts(ah, ah->imask);
|
||||
ath9k_hw_enable_interrupts(ah);
|
||||
}
|
||||
|
||||
static void ath_beacon_config_adhoc(struct ath_softc *sc,
|
||||
|
@ -687,12 +684,9 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
|
|||
ath9k_hw_disable_interrupts(ah);
|
||||
ath9k_beacon_init(sc, nexttbtt, intval);
|
||||
sc->beacon.bmisscnt = 0;
|
||||
/*
|
||||
* If the beacon config is called beacause of TSFOOR,
|
||||
* Interrupts will be enabled back at the end of ath9k_tasklet
|
||||
*/
|
||||
if (!(sc->ps_flags & PS_TSFOOR_SYNC))
|
||||
|
||||
ath9k_hw_set_interrupts(ah, ah->imask);
|
||||
ath9k_hw_enable_interrupts(ah);
|
||||
}
|
||||
|
||||
static bool ath9k_allow_beacon_config(struct ath_softc *sc,
|
||||
|
|
|
@ -63,6 +63,19 @@ static s16 ath9k_hw_get_default_nf(struct ath_hw *ah,
|
|||
return ath9k_hw_get_nf_limits(ah, chan)->nominal;
|
||||
}
|
||||
|
||||
s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan)
|
||||
{
|
||||
s8 noise = ATH_DEFAULT_NOISE_FLOOR;
|
||||
|
||||
if (chan && chan->noisefloor) {
|
||||
s8 delta = chan->noisefloor -
|
||||
ath9k_hw_get_default_nf(ah, chan);
|
||||
if (delta > 0)
|
||||
noise += delta;
|
||||
}
|
||||
return noise;
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_getchan_noise);
|
||||
|
||||
static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah,
|
||||
struct ath9k_hw_cal_data *cal,
|
||||
|
@ -378,6 +391,7 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)
|
|||
|
||||
if (!caldata) {
|
||||
chan->noisefloor = nf;
|
||||
ah->noise = ath9k_hw_getchan_noise(ah, chan);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -385,6 +399,7 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)
|
|||
caldata->nfcal_pending = false;
|
||||
ath9k_hw_update_nfcal_hist_buffer(ah, caldata, nfarray);
|
||||
chan->noisefloor = h[0].privNF;
|
||||
ah->noise = ath9k_hw_getchan_noise(ah, chan);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -108,6 +108,7 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
|
|||
void ath9k_hw_bstuck_nfcal(struct ath_hw *ah);
|
||||
void ath9k_hw_reset_calibration(struct ath_hw *ah,
|
||||
struct ath9k_cal_list *currCal);
|
||||
s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan);
|
||||
|
||||
|
||||
#endif /* CALIB_H */
|
||||
|
|
|
@ -1163,6 +1163,62 @@ static const struct file_operations fops_regdump = {
|
|||
.llseek = default_llseek,/* read accesses f_pos */
|
||||
};
|
||||
|
||||
static ssize_t read_file_base_eeprom(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath_softc *sc = file->private_data;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
u32 len = 0, size = 1500;
|
||||
ssize_t retval = 0;
|
||||
char *buf;
|
||||
|
||||
buf = kzalloc(size, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
len = ah->eep_ops->dump_eeprom(ah, true, buf, len, size);
|
||||
|
||||
retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
kfree(buf);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_base_eeprom = {
|
||||
.read = read_file_base_eeprom,
|
||||
.open = ath9k_debugfs_open,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t read_file_modal_eeprom(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath_softc *sc = file->private_data;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
u32 len = 0, size = 6000;
|
||||
char *buf;
|
||||
size_t retval;
|
||||
|
||||
buf = kzalloc(size, GFP_KERNEL);
|
||||
if (buf == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
len = ah->eep_ops->dump_eeprom(ah, false, buf, len, size);
|
||||
|
||||
retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
kfree(buf);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_modal_eeprom = {
|
||||
.read = read_file_modal_eeprom,
|
||||
.open = ath9k_debugfs_open,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
int ath9k_init_debug(struct ath_hw *ah)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
|
@ -1206,6 +1262,10 @@ int ath9k_init_debug(struct ath_hw *ah)
|
|||
&ah->config.cwm_ignore_extcca);
|
||||
debugfs_create_file("regdump", S_IRUSR, sc->debug.debugfs_phy, sc,
|
||||
&fops_regdump);
|
||||
debugfs_create_file("base_eeprom", S_IRUSR, sc->debug.debugfs_phy, sc,
|
||||
&fops_base_eeprom);
|
||||
debugfs_create_file("modal_eeprom", S_IRUSR, sc->debug.debugfs_phy, sc,
|
||||
&fops_modal_eeprom);
|
||||
|
||||
debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR,
|
||||
sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask);
|
||||
|
|
|
@ -649,6 +649,8 @@ struct eeprom_ops {
|
|||
int (*check_eeprom)(struct ath_hw *hw);
|
||||
u32 (*get_eeprom)(struct ath_hw *hw, enum eeprom_param param);
|
||||
bool (*fill_eeprom)(struct ath_hw *hw);
|
||||
u32 (*dump_eeprom)(struct ath_hw *hw, bool dump_base_hdr, u8 *buf,
|
||||
u32 len, u32 size);
|
||||
int (*get_eeprom_ver)(struct ath_hw *hw);
|
||||
int (*get_eeprom_rev)(struct ath_hw *hw);
|
||||
void (*set_board_values)(struct ath_hw *hw, struct ath9k_channel *chan);
|
||||
|
|
|
@ -72,6 +72,117 @@ static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah)
|
|||
return __ath9k_hw_4k_fill_eeprom(ah);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_ATH9K_DEBUGFS) || defined(CONFIG_ATH9K_HTC_DEBUGFS)
|
||||
static u32 ath9k_dump_4k_modal_eeprom(char *buf, u32 len, u32 size,
|
||||
struct modal_eep_4k_header *modal_hdr)
|
||||
{
|
||||
PR_EEP("Chain0 Ant. Control", modal_hdr->antCtrlChain[0]);
|
||||
PR_EEP("Ant. Common Control", modal_hdr->antCtrlCommon);
|
||||
PR_EEP("Chain0 Ant. Gain", modal_hdr->antennaGainCh[0]);
|
||||
PR_EEP("Switch Settle", modal_hdr->switchSettling);
|
||||
PR_EEP("Chain0 TxRxAtten", modal_hdr->txRxAttenCh[0]);
|
||||
PR_EEP("Chain0 RxTxMargin", modal_hdr->rxTxMarginCh[0]);
|
||||
PR_EEP("ADC Desired size", modal_hdr->adcDesiredSize);
|
||||
PR_EEP("PGA Desired size", modal_hdr->pgaDesiredSize);
|
||||
PR_EEP("Chain0 xlna Gain", modal_hdr->xlnaGainCh[0]);
|
||||
PR_EEP("txEndToXpaOff", modal_hdr->txEndToXpaOff);
|
||||
PR_EEP("txEndToRxOn", modal_hdr->txEndToRxOn);
|
||||
PR_EEP("txFrameToXpaOn", modal_hdr->txFrameToXpaOn);
|
||||
PR_EEP("CCA Threshold)", modal_hdr->thresh62);
|
||||
PR_EEP("Chain0 NF Threshold", modal_hdr->noiseFloorThreshCh[0]);
|
||||
PR_EEP("xpdGain", modal_hdr->xpdGain);
|
||||
PR_EEP("External PD", modal_hdr->xpd);
|
||||
PR_EEP("Chain0 I Coefficient", modal_hdr->iqCalICh[0]);
|
||||
PR_EEP("Chain0 Q Coefficient", modal_hdr->iqCalQCh[0]);
|
||||
PR_EEP("pdGainOverlap", modal_hdr->pdGainOverlap);
|
||||
PR_EEP("O/D Bias Version", modal_hdr->version);
|
||||
PR_EEP("CCK OutputBias", modal_hdr->ob_0);
|
||||
PR_EEP("BPSK OutputBias", modal_hdr->ob_1);
|
||||
PR_EEP("QPSK OutputBias", modal_hdr->ob_2);
|
||||
PR_EEP("16QAM OutputBias", modal_hdr->ob_3);
|
||||
PR_EEP("64QAM OutputBias", modal_hdr->ob_4);
|
||||
PR_EEP("CCK Driver1_Bias", modal_hdr->db1_0);
|
||||
PR_EEP("BPSK Driver1_Bias", modal_hdr->db1_1);
|
||||
PR_EEP("QPSK Driver1_Bias", modal_hdr->db1_2);
|
||||
PR_EEP("16QAM Driver1_Bias", modal_hdr->db1_3);
|
||||
PR_EEP("64QAM Driver1_Bias", modal_hdr->db1_4);
|
||||
PR_EEP("CCK Driver2_Bias", modal_hdr->db2_0);
|
||||
PR_EEP("BPSK Driver2_Bias", modal_hdr->db2_1);
|
||||
PR_EEP("QPSK Driver2_Bias", modal_hdr->db2_2);
|
||||
PR_EEP("16QAM Driver2_Bias", modal_hdr->db2_3);
|
||||
PR_EEP("64QAM Driver2_Bias", modal_hdr->db2_4);
|
||||
PR_EEP("xPA Bias Level", modal_hdr->xpaBiasLvl);
|
||||
PR_EEP("txFrameToDataStart", modal_hdr->txFrameToDataStart);
|
||||
PR_EEP("txFrameToPaOn", modal_hdr->txFrameToPaOn);
|
||||
PR_EEP("HT40 Power Inc.", modal_hdr->ht40PowerIncForPdadc);
|
||||
PR_EEP("Chain0 bswAtten", modal_hdr->bswAtten[0]);
|
||||
PR_EEP("Chain0 bswMargin", modal_hdr->bswMargin[0]);
|
||||
PR_EEP("HT40 Switch Settle", modal_hdr->swSettleHt40);
|
||||
PR_EEP("Chain0 xatten2Db", modal_hdr->xatten2Db[0]);
|
||||
PR_EEP("Chain0 xatten2Margin", modal_hdr->xatten2Margin[0]);
|
||||
PR_EEP("Ant. Diversity ctl1", modal_hdr->antdiv_ctl1);
|
||||
PR_EEP("Ant. Diversity ctl2", modal_hdr->antdiv_ctl2);
|
||||
PR_EEP("TX Diversity", modal_hdr->tx_diversity);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static u32 ath9k_hw_4k_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
|
||||
u8 *buf, u32 len, u32 size)
|
||||
{
|
||||
struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
|
||||
struct base_eep_header_4k *pBase = &eep->baseEepHeader;
|
||||
|
||||
if (!dump_base_hdr) {
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%20s :\n", "2GHz modal Header");
|
||||
len += ath9k_dump_4k_modal_eeprom(buf, len, size,
|
||||
&eep->modalHeader);
|
||||
goto out;
|
||||
}
|
||||
|
||||
PR_EEP("Major Version", pBase->version >> 12);
|
||||
PR_EEP("Minor Version", pBase->version & 0xFFF);
|
||||
PR_EEP("Checksum", pBase->checksum);
|
||||
PR_EEP("Length", pBase->length);
|
||||
PR_EEP("RegDomain1", pBase->regDmn[0]);
|
||||
PR_EEP("RegDomain2", pBase->regDmn[1]);
|
||||
PR_EEP("TX Mask", pBase->txMask);
|
||||
PR_EEP("RX Mask", pBase->rxMask);
|
||||
PR_EEP("Allow 5GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11A));
|
||||
PR_EEP("Allow 2GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11G));
|
||||
PR_EEP("Disable 2GHz HT20", !!(pBase->opCapFlags &
|
||||
AR5416_OPFLAGS_N_2G_HT20));
|
||||
PR_EEP("Disable 2GHz HT40", !!(pBase->opCapFlags &
|
||||
AR5416_OPFLAGS_N_2G_HT40));
|
||||
PR_EEP("Disable 5Ghz HT20", !!(pBase->opCapFlags &
|
||||
AR5416_OPFLAGS_N_5G_HT20));
|
||||
PR_EEP("Disable 5Ghz HT40", !!(pBase->opCapFlags &
|
||||
AR5416_OPFLAGS_N_5G_HT40));
|
||||
PR_EEP("Big Endian", !!(pBase->eepMisc & 0x01));
|
||||
PR_EEP("Cal Bin Major Ver", (pBase->binBuildNumber >> 24) & 0xFF);
|
||||
PR_EEP("Cal Bin Minor Ver", (pBase->binBuildNumber >> 16) & 0xFF);
|
||||
PR_EEP("Cal Bin Build", (pBase->binBuildNumber >> 8) & 0xFF);
|
||||
PR_EEP("TX Gain type", pBase->txGainType);
|
||||
|
||||
len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress",
|
||||
pBase->macAddr);
|
||||
|
||||
out:
|
||||
if (len > size)
|
||||
len = size;
|
||||
|
||||
return len;
|
||||
}
|
||||
#else
|
||||
static u32 ath9k_hw_4k_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
|
||||
u8 *buf, u32 len, u32 size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#undef SIZE_EEPROM_4K
|
||||
|
||||
static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
|
||||
|
@ -238,18 +349,14 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah,
|
|||
case EEP_ANT_DIV_CTL1:
|
||||
return pModal->antdiv_ctl1;
|
||||
case EEP_TXGAIN_TYPE:
|
||||
if (ver_minor >= AR5416_EEP_MINOR_VER_19)
|
||||
return pBase->txGainType;
|
||||
else
|
||||
return AR5416_EEP_TXGAIN_ORIGINAL;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
|
||||
struct ath9k_channel *chan,
|
||||
int16_t *pTxPowerIndexOffset)
|
||||
struct ath9k_channel *chan)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k;
|
||||
|
@ -356,8 +463,6 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
|
|||
REGWRITE_BUFFER_FLUSH(ah);
|
||||
}
|
||||
}
|
||||
|
||||
*pTxPowerIndexOffset = 0;
|
||||
}
|
||||
|
||||
static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
|
||||
|
@ -580,7 +685,6 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
|
|||
struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k;
|
||||
struct modal_eep_4k_header *pModal = &pEepData->modalHeader;
|
||||
int16_t ratesArray[Ar5416RateSize];
|
||||
int16_t txPowerIndexOffset = 0;
|
||||
u8 ht40PowerIncForPdadc = 2;
|
||||
int i;
|
||||
|
||||
|
@ -597,11 +701,10 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
|
|||
twiceMaxRegulatoryPower,
|
||||
powerLimit);
|
||||
|
||||
ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset);
|
||||
ath9k_hw_set_4k_power_cal_table(ah, chan);
|
||||
|
||||
regulatory->max_power_level = 0;
|
||||
for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
|
||||
ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
|
||||
if (ratesArray[i] > MAX_RATE_POWER)
|
||||
ratesArray[i] = MAX_RATE_POWER;
|
||||
|
||||
|
@ -612,15 +715,6 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
|
|||
if (test)
|
||||
return;
|
||||
|
||||
/* Update regulatory */
|
||||
i = rate6mb;
|
||||
if (IS_CHAN_HT40(chan))
|
||||
i = rateHt40_0;
|
||||
else if (IS_CHAN_HT20(chan))
|
||||
i = rateHt20_0;
|
||||
|
||||
regulatory->max_power_level = ratesArray[i];
|
||||
|
||||
if (AR_SREV_9280_20_OR_LATER(ah)) {
|
||||
for (i = 0; i < Ar5416RateSize; i++)
|
||||
ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2;
|
||||
|
@ -1063,6 +1157,7 @@ const struct eeprom_ops eep_4k_ops = {
|
|||
.check_eeprom = ath9k_hw_4k_check_eeprom,
|
||||
.get_eeprom = ath9k_hw_4k_get_eeprom,
|
||||
.fill_eeprom = ath9k_hw_4k_fill_eeprom,
|
||||
.dump_eeprom = ath9k_hw_4k_dump_eeprom,
|
||||
.get_eeprom_ver = ath9k_hw_4k_get_eeprom_ver,
|
||||
.get_eeprom_rev = ath9k_hw_4k_get_eeprom_rev,
|
||||
.set_board_values = ath9k_hw_4k_set_board_values,
|
||||
|
|
|
@ -76,6 +76,111 @@ static bool ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah)
|
|||
return __ath9k_hw_ar9287_fill_eeprom(ah);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_ATH9K_DEBUGFS) || defined(CONFIG_ATH9K_HTC_DEBUGFS)
|
||||
static u32 ar9287_dump_modal_eeprom(char *buf, u32 len, u32 size,
|
||||
struct modal_eep_ar9287_header *modal_hdr)
|
||||
{
|
||||
PR_EEP("Chain0 Ant. Control", modal_hdr->antCtrlChain[0]);
|
||||
PR_EEP("Chain1 Ant. Control", modal_hdr->antCtrlChain[1]);
|
||||
PR_EEP("Ant. Common Control", modal_hdr->antCtrlCommon);
|
||||
PR_EEP("Chain0 Ant. Gain", modal_hdr->antennaGainCh[0]);
|
||||
PR_EEP("Chain1 Ant. Gain", modal_hdr->antennaGainCh[1]);
|
||||
PR_EEP("Switch Settle", modal_hdr->switchSettling);
|
||||
PR_EEP("Chain0 TxRxAtten", modal_hdr->txRxAttenCh[0]);
|
||||
PR_EEP("Chain1 TxRxAtten", modal_hdr->txRxAttenCh[1]);
|
||||
PR_EEP("Chain0 RxTxMargin", modal_hdr->rxTxMarginCh[0]);
|
||||
PR_EEP("Chain1 RxTxMargin", modal_hdr->rxTxMarginCh[1]);
|
||||
PR_EEP("ADC Desired size", modal_hdr->adcDesiredSize);
|
||||
PR_EEP("txEndToXpaOff", modal_hdr->txEndToXpaOff);
|
||||
PR_EEP("txEndToRxOn", modal_hdr->txEndToRxOn);
|
||||
PR_EEP("txFrameToXpaOn", modal_hdr->txFrameToXpaOn);
|
||||
PR_EEP("CCA Threshold)", modal_hdr->thresh62);
|
||||
PR_EEP("Chain0 NF Threshold", modal_hdr->noiseFloorThreshCh[0]);
|
||||
PR_EEP("Chain1 NF Threshold", modal_hdr->noiseFloorThreshCh[1]);
|
||||
PR_EEP("xpdGain", modal_hdr->xpdGain);
|
||||
PR_EEP("External PD", modal_hdr->xpd);
|
||||
PR_EEP("Chain0 I Coefficient", modal_hdr->iqCalICh[0]);
|
||||
PR_EEP("Chain1 I Coefficient", modal_hdr->iqCalICh[1]);
|
||||
PR_EEP("Chain0 Q Coefficient", modal_hdr->iqCalQCh[0]);
|
||||
PR_EEP("Chain1 Q Coefficient", modal_hdr->iqCalQCh[1]);
|
||||
PR_EEP("pdGainOverlap", modal_hdr->pdGainOverlap);
|
||||
PR_EEP("xPA Bias Level", modal_hdr->xpaBiasLvl);
|
||||
PR_EEP("txFrameToDataStart", modal_hdr->txFrameToDataStart);
|
||||
PR_EEP("txFrameToPaOn", modal_hdr->txFrameToPaOn);
|
||||
PR_EEP("HT40 Power Inc.", modal_hdr->ht40PowerIncForPdadc);
|
||||
PR_EEP("Chain0 bswAtten", modal_hdr->bswAtten[0]);
|
||||
PR_EEP("Chain1 bswAtten", modal_hdr->bswAtten[1]);
|
||||
PR_EEP("Chain0 bswMargin", modal_hdr->bswMargin[0]);
|
||||
PR_EEP("Chain1 bswMargin", modal_hdr->bswMargin[1]);
|
||||
PR_EEP("HT40 Switch Settle", modal_hdr->swSettleHt40);
|
||||
PR_EEP("AR92x7 Version", modal_hdr->version);
|
||||
PR_EEP("DriverBias1", modal_hdr->db1);
|
||||
PR_EEP("DriverBias2", modal_hdr->db1);
|
||||
PR_EEP("CCK OutputBias", modal_hdr->ob_cck);
|
||||
PR_EEP("PSK OutputBias", modal_hdr->ob_psk);
|
||||
PR_EEP("QAM OutputBias", modal_hdr->ob_qam);
|
||||
PR_EEP("PAL_OFF OutputBias", modal_hdr->ob_pal_off);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static u32 ath9k_hw_ar9287_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
|
||||
u8 *buf, u32 len, u32 size)
|
||||
{
|
||||
struct ar9287_eeprom *eep = &ah->eeprom.map9287;
|
||||
struct base_eep_ar9287_header *pBase = &eep->baseEepHeader;
|
||||
|
||||
if (!dump_base_hdr) {
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%20s :\n", "2GHz modal Header");
|
||||
len += ar9287_dump_modal_eeprom(buf, len, size,
|
||||
&eep->modalHeader);
|
||||
goto out;
|
||||
}
|
||||
|
||||
PR_EEP("Major Version", pBase->version >> 12);
|
||||
PR_EEP("Minor Version", pBase->version & 0xFFF);
|
||||
PR_EEP("Checksum", pBase->checksum);
|
||||
PR_EEP("Length", pBase->length);
|
||||
PR_EEP("RegDomain1", pBase->regDmn[0]);
|
||||
PR_EEP("RegDomain2", pBase->regDmn[1]);
|
||||
PR_EEP("TX Mask", pBase->txMask);
|
||||
PR_EEP("RX Mask", pBase->rxMask);
|
||||
PR_EEP("Allow 5GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11A));
|
||||
PR_EEP("Allow 2GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11G));
|
||||
PR_EEP("Disable 2GHz HT20", !!(pBase->opCapFlags &
|
||||
AR5416_OPFLAGS_N_2G_HT20));
|
||||
PR_EEP("Disable 2GHz HT40", !!(pBase->opCapFlags &
|
||||
AR5416_OPFLAGS_N_2G_HT40));
|
||||
PR_EEP("Disable 5Ghz HT20", !!(pBase->opCapFlags &
|
||||
AR5416_OPFLAGS_N_5G_HT20));
|
||||
PR_EEP("Disable 5Ghz HT40", !!(pBase->opCapFlags &
|
||||
AR5416_OPFLAGS_N_5G_HT40));
|
||||
PR_EEP("Big Endian", !!(pBase->eepMisc & 0x01));
|
||||
PR_EEP("Cal Bin Major Ver", (pBase->binBuildNumber >> 24) & 0xFF);
|
||||
PR_EEP("Cal Bin Minor Ver", (pBase->binBuildNumber >> 16) & 0xFF);
|
||||
PR_EEP("Cal Bin Build", (pBase->binBuildNumber >> 8) & 0xFF);
|
||||
PR_EEP("Power Table Offset", pBase->pwrTableOffset);
|
||||
PR_EEP("OpenLoop Power Ctrl", pBase->openLoopPwrCntl);
|
||||
|
||||
len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress",
|
||||
pBase->macAddr);
|
||||
|
||||
out:
|
||||
if (len > size)
|
||||
len = size;
|
||||
|
||||
return len;
|
||||
}
|
||||
#else
|
||||
static u32 ath9k_hw_ar9287_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
|
||||
u8 *buf, u32 len, u32 size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah)
|
||||
{
|
||||
u32 sum = 0, el, integer;
|
||||
|
@ -307,8 +412,7 @@ static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah,
|
|||
}
|
||||
|
||||
static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah,
|
||||
struct ath9k_channel *chan,
|
||||
int16_t *pTxPowerIndexOffset)
|
||||
struct ath9k_channel *chan)
|
||||
{
|
||||
struct cal_data_per_freq_ar9287 *pRawDataset;
|
||||
struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop;
|
||||
|
@ -444,8 +548,6 @@ static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah,
|
|||
REGWRITE_BUFFER_FLUSH(ah);
|
||||
}
|
||||
}
|
||||
|
||||
*pTxPowerIndexOffset = 0;
|
||||
}
|
||||
|
||||
static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah,
|
||||
|
@ -720,7 +822,6 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah,
|
|||
struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
|
||||
struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader;
|
||||
int16_t ratesArray[Ar5416RateSize];
|
||||
int16_t txPowerIndexOffset = 0;
|
||||
u8 ht40PowerIncForPdadc = 2;
|
||||
int i;
|
||||
|
||||
|
@ -736,11 +837,10 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah,
|
|||
twiceMaxRegulatoryPower,
|
||||
powerLimit);
|
||||
|
||||
ath9k_hw_set_ar9287_power_cal_table(ah, chan, &txPowerIndexOffset);
|
||||
ath9k_hw_set_ar9287_power_cal_table(ah, chan);
|
||||
|
||||
regulatory->max_power_level = 0;
|
||||
for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
|
||||
ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
|
||||
if (ratesArray[i] > MAX_RATE_POWER)
|
||||
ratesArray[i] = MAX_RATE_POWER;
|
||||
|
||||
|
@ -751,13 +851,6 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah,
|
|||
if (test)
|
||||
return;
|
||||
|
||||
if (IS_CHAN_2GHZ(chan))
|
||||
i = rate1l;
|
||||
else
|
||||
i = rate6mb;
|
||||
|
||||
regulatory->max_power_level = ratesArray[i];
|
||||
|
||||
if (AR_SREV_9280_20_OR_LATER(ah)) {
|
||||
for (i = 0; i < Ar5416RateSize; i++)
|
||||
ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2;
|
||||
|
@ -1003,6 +1096,7 @@ const struct eeprom_ops eep_ar9287_ops = {
|
|||
.check_eeprom = ath9k_hw_ar9287_check_eeprom,
|
||||
.get_eeprom = ath9k_hw_ar9287_get_eeprom,
|
||||
.fill_eeprom = ath9k_hw_ar9287_fill_eeprom,
|
||||
.dump_eeprom = ath9k_hw_ar9287_dump_eeprom,
|
||||
.get_eeprom_ver = ath9k_hw_ar9287_get_eeprom_ver,
|
||||
.get_eeprom_rev = ath9k_hw_ar9287_get_eeprom_rev,
|
||||
.set_board_values = ath9k_hw_ar9287_set_board_values,
|
||||
|
|
|
@ -133,6 +133,136 @@ static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah)
|
|||
|
||||
#undef SIZE_EEPROM_DEF
|
||||
|
||||
#if defined(CONFIG_ATH9K_DEBUGFS) || defined(CONFIG_ATH9K_HTC_DEBUGFS)
|
||||
static u32 ath9k_def_dump_modal_eeprom(char *buf, u32 len, u32 size,
|
||||
struct modal_eep_header *modal_hdr)
|
||||
{
|
||||
PR_EEP("Chain0 Ant. Control", modal_hdr->antCtrlChain[0]);
|
||||
PR_EEP("Chain1 Ant. Control", modal_hdr->antCtrlChain[1]);
|
||||
PR_EEP("Chain2 Ant. Control", modal_hdr->antCtrlChain[2]);
|
||||
PR_EEP("Ant. Common Control", modal_hdr->antCtrlCommon);
|
||||
PR_EEP("Chain0 Ant. Gain", modal_hdr->antennaGainCh[0]);
|
||||
PR_EEP("Chain1 Ant. Gain", modal_hdr->antennaGainCh[1]);
|
||||
PR_EEP("Chain2 Ant. Gain", modal_hdr->antennaGainCh[2]);
|
||||
PR_EEP("Switch Settle", modal_hdr->switchSettling);
|
||||
PR_EEP("Chain0 TxRxAtten", modal_hdr->txRxAttenCh[0]);
|
||||
PR_EEP("Chain1 TxRxAtten", modal_hdr->txRxAttenCh[1]);
|
||||
PR_EEP("Chain2 TxRxAtten", modal_hdr->txRxAttenCh[2]);
|
||||
PR_EEP("Chain0 RxTxMargin", modal_hdr->rxTxMarginCh[0]);
|
||||
PR_EEP("Chain1 RxTxMargin", modal_hdr->rxTxMarginCh[1]);
|
||||
PR_EEP("Chain2 RxTxMargin", modal_hdr->rxTxMarginCh[2]);
|
||||
PR_EEP("ADC Desired size", modal_hdr->adcDesiredSize);
|
||||
PR_EEP("PGA Desired size", modal_hdr->pgaDesiredSize);
|
||||
PR_EEP("Chain0 xlna Gain", modal_hdr->xlnaGainCh[0]);
|
||||
PR_EEP("Chain1 xlna Gain", modal_hdr->xlnaGainCh[1]);
|
||||
PR_EEP("Chain2 xlna Gain", modal_hdr->xlnaGainCh[2]);
|
||||
PR_EEP("txEndToXpaOff", modal_hdr->txEndToXpaOff);
|
||||
PR_EEP("txEndToRxOn", modal_hdr->txEndToRxOn);
|
||||
PR_EEP("txFrameToXpaOn", modal_hdr->txFrameToXpaOn);
|
||||
PR_EEP("CCA Threshold)", modal_hdr->thresh62);
|
||||
PR_EEP("Chain0 NF Threshold", modal_hdr->noiseFloorThreshCh[0]);
|
||||
PR_EEP("Chain1 NF Threshold", modal_hdr->noiseFloorThreshCh[1]);
|
||||
PR_EEP("Chain2 NF Threshold", modal_hdr->noiseFloorThreshCh[2]);
|
||||
PR_EEP("xpdGain", modal_hdr->xpdGain);
|
||||
PR_EEP("External PD", modal_hdr->xpd);
|
||||
PR_EEP("Chain0 I Coefficient", modal_hdr->iqCalICh[0]);
|
||||
PR_EEP("Chain1 I Coefficient", modal_hdr->iqCalICh[1]);
|
||||
PR_EEP("Chain2 I Coefficient", modal_hdr->iqCalICh[2]);
|
||||
PR_EEP("Chain0 Q Coefficient", modal_hdr->iqCalQCh[0]);
|
||||
PR_EEP("Chain1 Q Coefficient", modal_hdr->iqCalQCh[1]);
|
||||
PR_EEP("Chain2 Q Coefficient", modal_hdr->iqCalQCh[2]);
|
||||
PR_EEP("pdGainOverlap", modal_hdr->pdGainOverlap);
|
||||
PR_EEP("Chain0 OutputBias", modal_hdr->ob);
|
||||
PR_EEP("Chain0 DriverBias", modal_hdr->db);
|
||||
PR_EEP("xPA Bias Level", modal_hdr->xpaBiasLvl);
|
||||
PR_EEP("2chain pwr decrease", modal_hdr->pwrDecreaseFor2Chain);
|
||||
PR_EEP("3chain pwr decrease", modal_hdr->pwrDecreaseFor3Chain);
|
||||
PR_EEP("txFrameToDataStart", modal_hdr->txFrameToDataStart);
|
||||
PR_EEP("txFrameToPaOn", modal_hdr->txFrameToPaOn);
|
||||
PR_EEP("HT40 Power Inc.", modal_hdr->ht40PowerIncForPdadc);
|
||||
PR_EEP("Chain0 bswAtten", modal_hdr->bswAtten[0]);
|
||||
PR_EEP("Chain1 bswAtten", modal_hdr->bswAtten[1]);
|
||||
PR_EEP("Chain2 bswAtten", modal_hdr->bswAtten[2]);
|
||||
PR_EEP("Chain0 bswMargin", modal_hdr->bswMargin[0]);
|
||||
PR_EEP("Chain1 bswMargin", modal_hdr->bswMargin[1]);
|
||||
PR_EEP("Chain2 bswMargin", modal_hdr->bswMargin[2]);
|
||||
PR_EEP("HT40 Switch Settle", modal_hdr->swSettleHt40);
|
||||
PR_EEP("Chain0 xatten2Db", modal_hdr->xatten2Db[0]);
|
||||
PR_EEP("Chain1 xatten2Db", modal_hdr->xatten2Db[1]);
|
||||
PR_EEP("Chain2 xatten2Db", modal_hdr->xatten2Db[2]);
|
||||
PR_EEP("Chain0 xatten2Margin", modal_hdr->xatten2Margin[0]);
|
||||
PR_EEP("Chain1 xatten2Margin", modal_hdr->xatten2Margin[1]);
|
||||
PR_EEP("Chain2 xatten2Margin", modal_hdr->xatten2Margin[2]);
|
||||
PR_EEP("Chain1 OutputBias", modal_hdr->ob_ch1);
|
||||
PR_EEP("Chain1 DriverBias", modal_hdr->db_ch1);
|
||||
PR_EEP("LNA Control", modal_hdr->lna_ctl);
|
||||
PR_EEP("XPA Bias Freq0", modal_hdr->xpaBiasLvlFreq[0]);
|
||||
PR_EEP("XPA Bias Freq1", modal_hdr->xpaBiasLvlFreq[1]);
|
||||
PR_EEP("XPA Bias Freq2", modal_hdr->xpaBiasLvlFreq[2]);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static u32 ath9k_hw_def_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
|
||||
u8 *buf, u32 len, u32 size)
|
||||
{
|
||||
struct ar5416_eeprom_def *eep = &ah->eeprom.def;
|
||||
struct base_eep_header *pBase = &eep->baseEepHeader;
|
||||
|
||||
if (!dump_base_hdr) {
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%20s :\n", "2GHz modal Header");
|
||||
len += ath9k_def_dump_modal_eeprom(buf, len, size,
|
||||
&eep->modalHeader[0]);
|
||||
len += snprintf(buf + len, size - len,
|
||||
"%20s :\n", "5GHz modal Header");
|
||||
len += ath9k_def_dump_modal_eeprom(buf, len, size,
|
||||
&eep->modalHeader[1]);
|
||||
goto out;
|
||||
}
|
||||
|
||||
PR_EEP("Major Version", pBase->version >> 12);
|
||||
PR_EEP("Minor Version", pBase->version & 0xFFF);
|
||||
PR_EEP("Checksum", pBase->checksum);
|
||||
PR_EEP("Length", pBase->length);
|
||||
PR_EEP("RegDomain1", pBase->regDmn[0]);
|
||||
PR_EEP("RegDomain2", pBase->regDmn[1]);
|
||||
PR_EEP("TX Mask", pBase->txMask);
|
||||
PR_EEP("RX Mask", pBase->rxMask);
|
||||
PR_EEP("Allow 5GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11A));
|
||||
PR_EEP("Allow 2GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11G));
|
||||
PR_EEP("Disable 2GHz HT20", !!(pBase->opCapFlags &
|
||||
AR5416_OPFLAGS_N_2G_HT20));
|
||||
PR_EEP("Disable 2GHz HT40", !!(pBase->opCapFlags &
|
||||
AR5416_OPFLAGS_N_2G_HT40));
|
||||
PR_EEP("Disable 5Ghz HT20", !!(pBase->opCapFlags &
|
||||
AR5416_OPFLAGS_N_5G_HT20));
|
||||
PR_EEP("Disable 5Ghz HT40", !!(pBase->opCapFlags &
|
||||
AR5416_OPFLAGS_N_5G_HT40));
|
||||
PR_EEP("Big Endian", !!(pBase->eepMisc & 0x01));
|
||||
PR_EEP("Cal Bin Major Ver", (pBase->binBuildNumber >> 24) & 0xFF);
|
||||
PR_EEP("Cal Bin Minor Ver", (pBase->binBuildNumber >> 16) & 0xFF);
|
||||
PR_EEP("Cal Bin Build", (pBase->binBuildNumber >> 8) & 0xFF);
|
||||
PR_EEP("OpenLoop Power Ctrl", pBase->openLoopPwrCntl);
|
||||
|
||||
len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress",
|
||||
pBase->macAddr);
|
||||
|
||||
out:
|
||||
if (len > size)
|
||||
len = size;
|
||||
|
||||
return len;
|
||||
}
|
||||
#else
|
||||
static u32 ath9k_hw_def_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
|
||||
u8 *buf, u32 len, u32 size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
|
||||
{
|
||||
struct ar5416_eeprom_def *eep =
|
||||
|
@ -693,8 +823,7 @@ static void ath9k_adjust_pdadc_values(struct ath_hw *ah,
|
|||
}
|
||||
|
||||
static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
|
||||
struct ath9k_channel *chan,
|
||||
int16_t *pTxPowerIndexOffset)
|
||||
struct ath9k_channel *chan)
|
||||
{
|
||||
#define SM_PD_GAIN(x) SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##x)
|
||||
#define SM_PDGAIN_B(x, y) \
|
||||
|
@ -855,7 +984,6 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
|
|||
}
|
||||
}
|
||||
|
||||
*pTxPowerIndexOffset = 0;
|
||||
#undef SM_PD_GAIN
|
||||
#undef SM_PDGAIN_B
|
||||
}
|
||||
|
@ -1143,7 +1271,6 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
|
|||
struct modal_eep_header *pModal =
|
||||
&(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]);
|
||||
int16_t ratesArray[Ar5416RateSize];
|
||||
int16_t txPowerIndexOffset = 0;
|
||||
u8 ht40PowerIncForPdadc = 2;
|
||||
int i, cck_ofdm_delta = 0;
|
||||
|
||||
|
@ -1160,28 +1287,16 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
|
|||
twiceMaxRegulatoryPower,
|
||||
powerLimit);
|
||||
|
||||
ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset);
|
||||
ath9k_hw_set_def_power_cal_table(ah, chan);
|
||||
|
||||
regulatory->max_power_level = 0;
|
||||
for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
|
||||
ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
|
||||
if (ratesArray[i] > MAX_RATE_POWER)
|
||||
ratesArray[i] = MAX_RATE_POWER;
|
||||
if (ratesArray[i] > regulatory->max_power_level)
|
||||
regulatory->max_power_level = ratesArray[i];
|
||||
}
|
||||
|
||||
if (!test) {
|
||||
i = rate6mb;
|
||||
|
||||
if (IS_CHAN_HT40(chan))
|
||||
i = rateHt40_0;
|
||||
else if (IS_CHAN_HT20(chan))
|
||||
i = rateHt20_0;
|
||||
|
||||
regulatory->max_power_level = ratesArray[i];
|
||||
}
|
||||
|
||||
switch(ar5416_get_ntxchains(ah->txchainmask)) {
|
||||
case 1:
|
||||
break;
|
||||
|
@ -1336,6 +1451,7 @@ const struct eeprom_ops eep_def_ops = {
|
|||
.check_eeprom = ath9k_hw_def_check_eeprom,
|
||||
.get_eeprom = ath9k_hw_def_get_eeprom,
|
||||
.fill_eeprom = ath9k_hw_def_fill_eeprom,
|
||||
.dump_eeprom = ath9k_hw_def_dump_eeprom,
|
||||
.get_eeprom_ver = ath9k_hw_def_get_eeprom_ver,
|
||||
.get_eeprom_rev = ath9k_hw_def_get_eeprom_rev,
|
||||
.set_board_values = ath9k_hw_def_set_board_values,
|
||||
|
|
|
@ -149,6 +149,7 @@ static void ath9k_gen_timer_start(struct ath_hw *ah,
|
|||
ath9k_hw_disable_interrupts(ah);
|
||||
ah->imask |= ATH9K_INT_GENTIMER;
|
||||
ath9k_hw_set_interrupts(ah, ah->imask);
|
||||
ath9k_hw_enable_interrupts(ah);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -163,6 +164,7 @@ static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
|
|||
ath9k_hw_disable_interrupts(ah);
|
||||
ah->imask &= ~ATH9K_INT_GENTIMER;
|
||||
ath9k_hw_set_interrupts(ah, ah->imask);
|
||||
ath9k_hw_enable_interrupts(ah);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -521,8 +521,6 @@ void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb,
|
|||
|
||||
int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv,
|
||||
u8 enable_coex);
|
||||
void ath9k_htc_station_work(struct work_struct *work);
|
||||
void ath9k_htc_aggr_work(struct work_struct *work);
|
||||
void ath9k_htc_ani_work(struct work_struct *work);
|
||||
void ath9k_htc_start_ani(struct ath9k_htc_priv *priv);
|
||||
void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv);
|
||||
|
@ -542,7 +540,6 @@ int ath9k_htc_tx_get_slot(struct ath9k_htc_priv *priv);
|
|||
void ath9k_htc_tx_clear_slot(struct ath9k_htc_priv *priv, int slot);
|
||||
void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv);
|
||||
void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event);
|
||||
void ath9k_htc_tx_failed(struct ath9k_htc_priv *priv);
|
||||
void ath9k_tx_failed_tasklet(unsigned long data);
|
||||
void ath9k_htc_tx_cleanup_timer(unsigned long data);
|
||||
|
||||
|
|
|
@ -666,7 +666,6 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
|
|||
return -ENOMEM;
|
||||
|
||||
ah->hw_version.devid = devid;
|
||||
ah->hw_version.subsysid = 0; /* FIXME */
|
||||
ah->hw_version.usbdev = drv_info;
|
||||
ah->ah_flags |= AH_USE_EEPROM;
|
||||
ah->reg_ops.read = ath9k_regread;
|
||||
|
|
|
@ -1486,6 +1486,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
|||
memset(caldata, 0, sizeof(*caldata));
|
||||
ath9k_init_nfcal_hist_buffer(ah, chan);
|
||||
}
|
||||
ah->noise = ath9k_hw_getchan_noise(ah, chan);
|
||||
|
||||
if (bChannelChange &&
|
||||
(ah->chip_fullsleep != true) &&
|
||||
|
@ -2439,15 +2440,18 @@ void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test)
|
|||
struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
|
||||
struct ath9k_channel *chan = ah->curchan;
|
||||
struct ieee80211_channel *channel = chan->chan;
|
||||
int reg_pwr = min_t(int, MAX_RATE_POWER, regulatory->power_limit);
|
||||
int chan_pwr = channel->max_power * 2;
|
||||
|
||||
if (test)
|
||||
reg_pwr = chan_pwr = MAX_RATE_POWER;
|
||||
|
||||
regulatory->power_limit = min(limit, (u32) MAX_RATE_POWER);
|
||||
|
||||
ah->eep_ops->set_txpower(ah, chan,
|
||||
ath9k_regd_get_ctl(regulatory, chan),
|
||||
channel->max_antenna_gain * 2,
|
||||
channel->max_power * 2,
|
||||
min((u32) MAX_RATE_POWER,
|
||||
(u32) regulatory->power_limit), test);
|
||||
chan_pwr, reg_pwr, test);
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_set_txpowerlimit);
|
||||
|
||||
|
|
|
@ -93,6 +93,12 @@
|
|||
(_ah)->reg_ops.write_flush((_ah)); \
|
||||
} while (0)
|
||||
|
||||
#define PR_EEP(_s, _val) \
|
||||
do { \
|
||||
len += snprintf(buf + len, size - len, "%20s : %10d\n", \
|
||||
_s, (_val)); \
|
||||
} while (0)
|
||||
|
||||
#define SM(_v, _f) (((_v) << _f##_S) & _f)
|
||||
#define MS(_v, _f) (((_v) & _f) >> _f##_S)
|
||||
#define REG_RMW_FIELD(_a, _r, _f, _v) \
|
||||
|
@ -438,7 +444,6 @@ struct ath9k_hw_version {
|
|||
u16 phyRev;
|
||||
u16 analog5GhzRev;
|
||||
u16 analog2GhzRev;
|
||||
u16 subsysid;
|
||||
enum ath_usb_dev usbdev;
|
||||
};
|
||||
|
||||
|
@ -690,6 +695,7 @@ struct ath_hw {
|
|||
enum nl80211_iftype opmode;
|
||||
enum ath9k_power_mode power_mode;
|
||||
|
||||
s8 noise;
|
||||
struct ath9k_hw_cal_data *caldata;
|
||||
struct ath9k_pacal_info pacal_info;
|
||||
struct ar5416Stats stats;
|
||||
|
@ -703,6 +709,7 @@ struct ath_hw {
|
|||
u32 txdesc_interrupt_mask;
|
||||
u32 txeol_interrupt_mask;
|
||||
u32 txurn_interrupt_mask;
|
||||
atomic_t intr_ref_cnt;
|
||||
bool chip_fullsleep;
|
||||
u32 atim_window;
|
||||
|
||||
|
|
|
@ -548,7 +548,7 @@ static void ath9k_init_misc(struct ath_softc *sc)
|
|||
sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT;
|
||||
}
|
||||
|
||||
static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
|
||||
static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
|
||||
const struct ath_bus_ops *bus_ops)
|
||||
{
|
||||
struct ath9k_platform_data *pdata = sc->dev->platform_data;
|
||||
|
@ -563,10 +563,10 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
|
|||
|
||||
ah->hw = sc->hw;
|
||||
ah->hw_version.devid = devid;
|
||||
ah->hw_version.subsysid = subsysid;
|
||||
ah->reg_ops.read = ath9k_ioread32;
|
||||
ah->reg_ops.write = ath9k_iowrite32;
|
||||
ah->reg_ops.rmw = ath9k_reg_rmw;
|
||||
atomic_set(&ah->intr_ref_cnt, -1);
|
||||
sc->sc_ah = ah;
|
||||
|
||||
if (!pdata) {
|
||||
|
@ -743,7 +743,7 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
|
|||
SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
|
||||
}
|
||||
|
||||
int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
|
||||
int ath9k_init_device(u16 devid, struct ath_softc *sc,
|
||||
const struct ath_bus_ops *bus_ops)
|
||||
{
|
||||
struct ieee80211_hw *hw = sc->hw;
|
||||
|
@ -753,7 +753,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
|
|||
struct ath_regulatory *reg;
|
||||
|
||||
/* Bring up device */
|
||||
error = ath9k_init_softc(devid, sc, subsysid, bus_ops);
|
||||
error = ath9k_init_softc(devid, sc, bus_ops);
|
||||
if (error != 0)
|
||||
goto error_init;
|
||||
|
||||
|
|
|
@ -800,6 +800,11 @@ void ath9k_hw_disable_interrupts(struct ath_hw *ah)
|
|||
{
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
|
||||
if (!(ah->imask & ATH9K_INT_GLOBAL))
|
||||
atomic_set(&ah->intr_ref_cnt, -1);
|
||||
else
|
||||
atomic_dec(&ah->intr_ref_cnt);
|
||||
|
||||
ath_dbg(common, ATH_DBG_INTERRUPT, "disable IER\n");
|
||||
REG_WRITE(ah, AR_IER, AR_IER_DISABLE);
|
||||
(void) REG_READ(ah, AR_IER);
|
||||
|
@ -821,6 +826,13 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah)
|
|||
if (!(ah->imask & ATH9K_INT_GLOBAL))
|
||||
return;
|
||||
|
||||
if (!atomic_inc_and_test(&ah->intr_ref_cnt)) {
|
||||
ath_dbg(common, ATH_DBG_INTERRUPT,
|
||||
"Do not enable IER ref count %d\n",
|
||||
atomic_read(&ah->intr_ref_cnt));
|
||||
return;
|
||||
}
|
||||
|
||||
if (AR_SREV_9340(ah))
|
||||
sync_default &= ~AR_INTR_SYNC_HOST1_FATAL;
|
||||
|
||||
|
@ -852,7 +864,6 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
|
|||
|
||||
ath_dbg(common, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints);
|
||||
|
||||
/* TODO: global int Ref count */
|
||||
mask = ints & ATH9K_INT_COMMON;
|
||||
mask2 = 0;
|
||||
|
||||
|
@ -929,9 +940,6 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
|
|||
REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER);
|
||||
}
|
||||
|
||||
if (ints & ATH9K_INT_GLOBAL)
|
||||
ath9k_hw_enable_interrupts(ah);
|
||||
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_set_interrupts);
|
||||
|
|
|
@ -163,7 +163,7 @@ static void ath_update_survey_nf(struct ath_softc *sc, int channel)
|
|||
|
||||
if (chan->noisefloor) {
|
||||
survey->filled |= SURVEY_INFO_NOISE_DBM;
|
||||
survey->noise = chan->noisefloor;
|
||||
survey->noise = ath9k_hw_getchan_noise(ah, chan);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -294,6 +294,7 @@ static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
|
|||
ath9k_cmn_update_txpow(ah, sc->curtxpow,
|
||||
sc->config.txpowlimit, &sc->curtxpow);
|
||||
ath9k_hw_set_interrupts(ah, ah->imask);
|
||||
ath9k_hw_enable_interrupts(ah);
|
||||
|
||||
if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) {
|
||||
if (sc->sc_flags & SC_OP_BEACONS)
|
||||
|
@ -706,8 +707,7 @@ void ath9k_tasklet(unsigned long data)
|
|||
*/
|
||||
ath_dbg(common, ATH_DBG_PS,
|
||||
"TSFOOR - Sync with next Beacon\n");
|
||||
sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC |
|
||||
PS_TSFOOR_SYNC;
|
||||
sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC;
|
||||
}
|
||||
|
||||
if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
|
||||
|
@ -886,6 +886,7 @@ static void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
|
|||
|
||||
ath9k_ps_wakeup(sc);
|
||||
spin_lock_bh(&sc->sc_pcu_lock);
|
||||
atomic_set(&ah->intr_ref_cnt, -1);
|
||||
|
||||
ath9k_hw_configpcipowersave(ah, 0, 0);
|
||||
|
||||
|
@ -910,6 +911,7 @@ static void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
|
|||
|
||||
/* Re-Enable interrupts */
|
||||
ath9k_hw_set_interrupts(ah, ah->imask);
|
||||
ath9k_hw_enable_interrupts(ah);
|
||||
|
||||
/* Enable LED */
|
||||
ath9k_hw_cfg_output(ah, ah->led_pin,
|
||||
|
@ -1016,6 +1018,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
|
|||
ath_set_beacon(sc); /* restart beacons */
|
||||
|
||||
ath9k_hw_set_interrupts(ah, ah->imask);
|
||||
ath9k_hw_enable_interrupts(ah);
|
||||
|
||||
if (retry_tx) {
|
||||
int i;
|
||||
|
@ -1130,6 +1133,7 @@ static int ath9k_start(struct ieee80211_hw *hw)
|
|||
/* Disable BMISS interrupt when we're not associated */
|
||||
ah->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
|
||||
ath9k_hw_set_interrupts(ah, ah->imask);
|
||||
ath9k_hw_enable_interrupts(ah);
|
||||
|
||||
ieee80211_wake_queues(hw);
|
||||
|
||||
|
|
|
@ -156,7 +156,6 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
struct ath_softc *sc;
|
||||
struct ieee80211_hw *hw;
|
||||
u8 csz;
|
||||
u16 subsysid;
|
||||
u32 val;
|
||||
int ret = 0;
|
||||
char hw_name[64];
|
||||
|
@ -250,8 +249,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
|
||||
sc->irq = pdev->irq;
|
||||
|
||||
pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsysid);
|
||||
ret = ath9k_init_device(id->device, sc, subsysid, &ath_pci_bus_ops);
|
||||
ret = ath9k_init_device(id->device, sc, &ath_pci_bus_ops);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to initialize device\n");
|
||||
goto err_init;
|
||||
|
|
|
@ -1484,7 +1484,7 @@ static ssize_t read_file_rcstat(struct file *file, char __user *user_buf,
|
|||
if (rc->rate_table == NULL)
|
||||
return 0;
|
||||
|
||||
max = 80 + rc->rate_table->rate_cnt * 1024 + 1;
|
||||
max = 80 + rc->rate_table_size * 1024 + 1;
|
||||
buf = kmalloc(max, GFP_KERNEL);
|
||||
if (buf == NULL)
|
||||
return -ENOMEM;
|
||||
|
@ -1494,7 +1494,7 @@ static ssize_t read_file_rcstat(struct file *file, char __user *user_buf,
|
|||
"HT", "MCS", "Rate",
|
||||
"Success", "Retries", "XRetries", "PER");
|
||||
|
||||
for (i = 0; i < rc->rate_table->rate_cnt; i++) {
|
||||
for (i = 0; i < rc->rate_table_size; i++) {
|
||||
u32 ratekbps = rc->rate_table->info[i].ratekbps;
|
||||
struct ath_rc_stats *stats = &rc->rcstats[i];
|
||||
char mcs[5];
|
||||
|
|
|
@ -221,12 +221,6 @@ struct ath_rate_priv {
|
|||
struct ath_rc_stats rcstats[RATE_TABLE_SIZE];
|
||||
};
|
||||
|
||||
enum ath9k_internal_frame_type {
|
||||
ATH9K_IFT_NOT_INTERNAL,
|
||||
ATH9K_IFT_PAUSE,
|
||||
ATH9K_IFT_UNPAUSE
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ATH9K_RATE_CONTROL
|
||||
int ath_rate_control_register(void);
|
||||
void ath_rate_control_unregister(void);
|
||||
|
|
|
@ -601,7 +601,6 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
|
|||
ath_dbg(common, ATH_DBG_PS,
|
||||
"Reconfigure Beacon timers based on timestamp from the AP\n");
|
||||
ath_set_beacon(sc);
|
||||
sc->ps_flags &= ~PS_TSFOOR_SYNC;
|
||||
}
|
||||
|
||||
if (ath_beacon_dtim_pending_cab(skb)) {
|
||||
|
@ -995,6 +994,8 @@ static int ath9k_rx_skb_preprocess(struct ath_common *common,
|
|||
struct ieee80211_rx_status *rx_status,
|
||||
bool *decrypt_error)
|
||||
{
|
||||
struct ath_hw *ah = common->ah;
|
||||
|
||||
memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
|
||||
|
||||
/*
|
||||
|
@ -1015,7 +1016,7 @@ static int ath9k_rx_skb_preprocess(struct ath_common *common,
|
|||
|
||||
rx_status->band = hw->conf.channel->band;
|
||||
rx_status->freq = hw->conf.channel->center_freq;
|
||||
rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + rx_stats->rs_rssi;
|
||||
rx_status->signal = ah->noise + rx_stats->rs_rssi;
|
||||
rx_status->antenna = rx_stats->rs_antenna;
|
||||
rx_status->flag |= RX_FLAG_MACTIME_MPDU;
|
||||
|
||||
|
@ -1783,11 +1784,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
|
|||
struct ieee80211_rx_status *rxs;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
/*
|
||||
* The hw can technically differ from common->hw when using ath9k
|
||||
* virtual wiphy so to account for that we iterate over the active
|
||||
* wiphys and find the appropriate wiphy and therefore hw.
|
||||
*/
|
||||
struct ieee80211_hw *hw = sc->hw;
|
||||
struct ieee80211_hdr *hdr;
|
||||
int retval;
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче