提交 b38d355e 编写于 作者: J John W. Linville

Merge branch 'master' of...

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

Conflicts:
	drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.c
	drivers/staging/ath6kl/os/linux/ar6000_drv.c
上级 ca1ba7ca af2bf4b4
master alk-4.19.24 alk-4.19.30 alk-4.19.34 alk-4.19.36 alk-4.19.43 alk-4.19.48 alk-4.19.57 ck-4.19.67 ck-4.19.81 ck-4.19.91 github/fork/deepanshu1422/fix-typo-in-comment github/fork/haosdent/fix-typo linux-next v4.19.91 v4.19.90 v4.19.89 v4.19.88 v4.19.87 v4.19.86 v4.19.85 v4.19.84 v4.19.83 v4.19.82 v4.19.81 v4.19.80 v4.19.79 v4.19.78 v4.19.77 v4.19.76 v4.19.75 v4.19.74 v4.19.73 v4.19.72 v4.19.71 v4.19.70 v4.19.69 v4.19.68 v4.19.67 v4.19.66 v4.19.65 v4.19.64 v4.19.63 v4.19.62 v4.19.61 v4.19.60 v4.19.59 v4.19.58 v4.19.57 v4.19.56 v4.19.55 v4.19.54 v4.19.53 v4.19.52 v4.19.51 v4.19.50 v4.19.49 v4.19.48 v4.19.47 v4.19.46 v4.19.45 v4.19.44 v4.19.43 v4.19.42 v4.19.41 v4.19.40 v4.19.39 v4.19.38 v4.19.37 v4.19.36 v4.19.35 v4.19.34 v4.19.33 v4.19.32 v4.19.31 v4.19.30 v4.19.29 v4.19.28 v4.19.27 v4.19.26 v4.19.25 v4.19.24 v4.19.23 v4.19.22 v4.19.21 v4.19.20 v4.19.19 v4.19.18 v4.19.17 v4.19.16 v4.19.15 v4.19.14 v4.19.13 v4.19.12 v4.19.11 v4.19.10 v4.19.9 v4.19.8 v4.19.7 v4.19.6 v4.19.5 v4.19.4 v4.19.3 v4.19.2 v4.19.1 v4.19 v4.19-rc8 v4.19-rc7 v4.19-rc6 v4.19-rc5 v4.19-rc4 v4.19-rc3 v4.19-rc2 v4.19-rc1 ck-release-21 ck-release-20 ck-release-19.2 ck-release-19.1 ck-release-19 ck-release-18 ck-release-17.2 ck-release-17.1 ck-release-17 ck-release-16 ck-release-15.1 ck-release-15 ck-release-14 ck-release-13.2 ck-release-13 ck-release-12 ck-release-11 ck-release-10 ck-release-9 ck-release-7 alk-release-15 alk-release-14 alk-release-13.2 alk-release-13 alk-release-12 alk-release-11 alk-release-10 alk-release-9 alk-release-7
无相关合并请求
......@@ -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"
......
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,42 +20,82 @@ 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) &&
((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
return -EINVAL;
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) &&
((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
return -EINVAL;
if (ssb_extif_available(&bcm47xx_bus.ssb.extif) &&
((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
return -EINVAL;
if (test_and_set_bit(gpio, gpio_in_use))
return -EBUSY;
if (test_and_set_bit(gpio, gpio_in_use))
return -EBUSY;
return 0;
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) &&
((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
return;
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(&bcm47xx_bus.ssb.extif) &&
((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
return;
if (ssb_extif_available(&ssb_bcm47xx.extif) &&
((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
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);
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;
else
return -EINVAL;
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 = &current_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);
return 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)
{
/* first set the gpio out value */
ssb_gpio_out(&ssb_bcm47xx, 1 << gpio, value ? 1 << gpio : 0);
/* then set the gpio mode */
ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 1 << gpio);
return 0;
switch (bcm47xx_bus_type) {
#ifdef CONFIG_BCM47XX_SSB
case BCM47XX_BUS_TYPE_SSB:
/* first set the gpio out value */
ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio,
value ? 1 << gpio : 0);
/* then set the gpio mode */
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,
value ? 1 << gpio : 0);
return 0;
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,
value ? 1 << gpio : 0);
return 0;
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);
}
/*
* 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)
......
/*
* 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,18 +200,162 @@ 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];
/* get CIs */
cia = bcma_erom_get_ci(bus, eromptr);
if (cia < 0) {
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;
core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
if (((core->id.manuf == BCMA_MANUF_ARM) &&
(core->id.id == 0xFFF)) ||
(ports[1] == 0)) {
bcma_erom_skip_component(bus, eromptr);
return -ENXIO;
}
/* check if component is a core at all */
if (wrappers[0] + wrappers[1] == 0) {
/* we could save addrl of the router
if (cid == BCMA_CORE_OOB_ROUTER)
*/
bcma_erom_skip_component(bus, eromptr);
return -ENXIO;
}
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)
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,
SCAN_ADDR_TYPE_SLAVE, i);
if (tmp < 0) {
/* no more entries for port _i_ */
/* pr_debug("erom: slave port %d "
* "has %d descriptors\n", i, j); */
break;
} else {
if (i == 0 && j == 0)
core->addr = tmp;
}
}
}
/* get & parse master wrappers */
for (i = 0; i < wrappers[0]; i++) {
for (j = 0; ; j++) {
tmp = bcma_erom_get_addr_desc(bus, eromptr,
SCAN_ADDR_TYPE_MWRAP, i);
if (tmp < 0) {
/* no more entries for port _i_ */
/* pr_debug("erom: master wrapper %d "
* "has %d descriptors\n", i, j); */
break;
} else {
if (i == 0 && j == 0)
core->wrap = tmp;
}
}
}
/* get & parse slave wrappers */
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,
SCAN_ADDR_TYPE_SWRAP, i + hack);
if (tmp < 0) {
/* no more entries for port _i_ */
/* pr_debug("erom: master wrapper %d "
* has %d descriptors\n", i, j); */
break;
} else {
if (wrappers[0] == 0 && !i && !j)
core->wrap = tmp;
}
}
}
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;
u8 i, j;
int err;
if (bus->init_done)
return;
INIT_LIST_HEAD(&bus->cores);
bus->nr_cores = 0;
......@@ -222,9 +366,27 @@ int bcma_bus_scan(struct bcma_bus *bus)
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);
eromptr = bus->mmio;
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);
......@@ -236,125 +398,89 @@ int bcma_bus_scan(struct bcma_bus *bus)
INIT_LIST_HEAD(&core->list);
core->bus = bus;
/* get CIs */
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;
}
/* parse CIs */
core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
if (((core->id.manuf == BCMA_MANUF_ARM) &&
(core->id.id == 0xFFF)) ||
(ports[1] == 0)) {
bcma_erom_skip_component(bus, &eromptr);
err = bcma_get_next_core(bus, &eromptr, NULL, core_num, core);
if (err == -ENODEV) {
core_num++;
continue;
}
/* check if component is a core at all */
if (wrappers[0] + wrappers[1] == 0) {
/* we could save addrl of the router
if (cid == BCMA_CORE_OOB_ROUTER)
*/
bcma_erom_skip_component(bus, &eromptr);
} else if (err == -ENXIO)
continue;
}
else if (err == -ESPIPE)
break;
else if (err < 0)
return err;
if (bcma_erom_is_bridge(bus, &eromptr)) {
bcma_erom_skip_component(bus, &eromptr);
continue;
}
core->core_index = core_num++;
bus->nr_cores++;
/* 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;
}
}
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);
/* get & parse slave ports */
for (i = 0; i < ports[1]; i++) {
for (j = 0; ; j++) {
tmp = bcma_erom_get_addr_desc(bus, &eromptr,
SCAN_ADDR_TYPE_SLAVE, i);
if (tmp < 0) {
/* no more entries for port _i_ */
/* pr_debug("erom: slave port %d "
* "has %d descriptors\n", i, j); */
break;
} else {
if (i == 0 && j == 0)
core->addr = tmp;
}
}
}
list_add(&core->list, &bus->cores);
}
/* get & parse master wrappers */
for (i = 0; i < wrappers[0]; i++) {
for (j = 0; ; j++) {
tmp = bcma_erom_get_addr_desc(bus, &eromptr,
SCAN_ADDR_TYPE_MWRAP, i);
if (tmp < 0) {
/* no more entries for port _i_ */
/* pr_debug("erom: master wrapper %d "
* "has %d descriptors\n", i, j); */
break;
} else {
if (i == 0 && j == 0)
core->wrap = tmp;
}
}
}
if (bus->hosttype == BCMA_HOSTTYPE_SOC)
iounmap(eromptr);
/* get & parse slave wrappers */
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,
SCAN_ADDR_TYPE_SWRAP, i + hack);
if (tmp < 0) {
/* no more entries for port _i_ */
/* pr_debug("erom: master wrapper %d "
* has %d descriptors\n", i, j); */
break;
} else {
if (wrappers[0] == 0 && !i && !j)
core->wrap = tmp;
}
}
}
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",
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;
err = 0;
break;
}
return 0;
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
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 @@ ath5k_init(struct ieee80211_hw *hw)
}
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);
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)) {
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;
} else if (channel->hw_value & CHANNEL_2GHZ) {
break;
case AR5K_EEPROM_MODE_11G:
default:
pcinfo = ee->ee_pwr_cal_g;
mode = AR5K_EEPROM_MODE_11G;
} else {
pcinfo = ee->ee_pwr_cal_a;
mode = AR5K_EEPROM_MODE_11A;
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)) {
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;
} else if (channel->hw_value & CHANNEL_2GHZ) {
break;
case AR5K_MODE_11G:
default:
rpinfo = ee->ee_rate_tpwr_g;
mode = AR5K_EEPROM_MODE_11G;
} else {
rpinfo = ee->ee_rate_tpwr_a;
mode = AR5K_EEPROM_MODE_11A;
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)
......
#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
......
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
#------------------------------------------------------------------------------
# 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
/*
* 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]), &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;
}
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;
}
/*
* 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
此差异已折叠。
/*
* 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 */
/*
* 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 */
/*
* 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 */
/*
* 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
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -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;
......
......@@ -531,17 +531,18 @@ 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 ((rxsp->status11 & AR_RxDone) == 0)
return -EINPROGRESS;
if (!rxs) {
if ((rxsp->status11 & AR_RxDone) == 0)
return -EINPROGRESS;
if (MS(rxsp->ds_info, AR_DescId) != 0x168c)
return -EINVAL;
if (MS(rxsp->ds_info, AR_DescId) != 0x168c)
return -EINVAL;
if ((rxsp->ds_info & (AR_TxRxDesc | AR_CtrlStat)) != 0)
return -EINPROGRESS;
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;
}
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册
反馈
建议
客服 返回
顶部